gug-doc

59
Documentation Draft SinnerSchrader Gucci Group projects 2011 Felix Abraham et.al. 1

Transcript of gug-doc

Page 1: gug-doc

Documentation

Draft

SinnerSchrader

Gucci Group projects

2011

Felix Abraham etal

1

Index11 Hello World - How do I create a new page5

Motivation context problem scenario5Defining the URLs routes5

Routes routing6Backend controller8Templating10Helper classes12i18n internationalization12Folder structure13

12 Use case Product detail page13Motivation context problem scenario13Preconditions prior knowledge13

Demandware products14Import15GlobalData15

Implementation16Backend16Frontend17

13 Use case Category page17Motivation context problem scenario18Preconditions prior knowledge18Implementation18

Server-side implementation18Client-side implementation20

14 Use case Checkout20Motivation context problem scenario20Preconditions prior knowledge20

Functional requirements20Demandware settings20

Implementation21Gift option22Coupon codes22Personal customer data (may need registration login)22Address details (shipment billing address)23Shipping types23Payment types24Order completion24

21 Reference for CurrentMasterProduct and CurrentVariantProduct24Structure and properties25Creating objects for products26

Example 1 Creating a product with a master ID26Example 2 Creating a product with a variant ID27

2

22 Recipe Content asset with jsonContent27Motivation context problem scenario27Solution model28Implementation28Advantages28Disadvantages29Outlook29

23 Recipe Product detail page with globalData29Motivation context problem scenario29Solution model30Implementation30

24 Use case Send email30Motivation context problem scenario31Preconditions prior knowledge31Overview of steps to be completed31

a) Configuration of MVCPipes31b) Creation of a sendMailTo() helper method32c) Implementation of the SendEmail helper in the controller of the relevant page32d) Creation of an asset in Demandware Business Manager34

email_tell_a_friend asset34Integration of asset within template35

e) Creation of a business object in order to be able to validate and subsequently access data from the form35

31 Use case Frontend controller36Motivation context problem scenario36Preconditions prior knowledge37Implementation37

Creating the basic framework37The rootNode property38ready() and nodeReady()38Accessing return values from the backend controller38Sub-methods38has properties39Access to Weet URLs39Access to widgets and inits39

32 Use case Sharable widget40Motivation context problem scenario40Preconditions prior knowledge40Embedding the Sharable widget40

Creating the basic framework4033 Recipe Sharing a product page41

Motivation context problem scenario41Various solutions41

a) Facebook Like button41

3

b) FacebookTwitter share link42c) Others42

Outlook4334 Use Case Frontend JavaScript inits43

Motivation context problem scenario43Conventions43Solution model 1 Simple init (without Joose class)43Solution model 2 Complex init (with Joose class)43Implementation44Advantages44Disadvantages44Outlook44

35 Use Case Frontend JavaScript widgets45Motivation context problem scenario45Conventions45Solution model 1 Simple widgets (without Joose class)45Solution model 2 Complex widgets (with Joose class)45Implementation46Advantages46Disadvantages47Outlook47

36 Use case Video player init47Motivation context problem scenario47Preconditions prior knowledge47Embedding the video player init47

Creating the basic framework484 Recipe CSS48

Motivation context problem scenario49The use of LESS-CSS49

Client-side usage49Splitting of CSS files49CSS structure50

Conventions50Conversion for use in a live context51

5 Use case Make AMS content maintainable51Motivation context problem scenario51Creating a page in AMS51Qooxdoo window52

Template52Qooxdoo model53

Document53Node Exporter54

Export54

4

11 Hello World - How do I create a new page

This documentation is intended to show you how to create a page as well as the steps that are necessary to ensure that the desired result is provided at your chosen URL

By applying this information the reader should be capable of defining a URL implementing the logic at the appropriate place and producing a template for presenting the page

Motivation context problem scenario

Starting from scratch can be quite difficult This chapter helps with the first steps that are necessary to create a website following the same principles that apply to all Gucci shops created by SinnerSchrader The main intention here is not so much showing the various aspects and concepts of Demandware but rather to present those that have been used and are important in shops created by SinnerSchrader

Defining the URLs routes

Unlike standard Demandware implementations we will not be using the graphical pipelines Instead we have constructed an MVC framework that provides the range of options with which you will be familiar as a web developer

The graphical pipelines have a number of disadvantages First they are highly static and difficult to maintain Above all however it is also theoretically impossible to work on a pipeline with multiple developers The reason for this is that even the repositioning of a single pipelet leads to changes at various places in the XML file ndash a file in which the pipeline is ultimately saved This leads to a situation where conflicts that occur when merging before checking-in to a shared repository are very difficult ndash or impossible ndash to resolve In addition the URLs that result from the pipeline model are strictly predefined (demandwarePIPELINENAME-ACTION)

The MVC framework that has been implemented here permits the user-friendly definition of any number of URLs in the form of regular expressions Routing functionality is also provided that permits the centralized definition of URL patterns for particular functions

The end result is a powerful tool for defining any number of URL patterns in a simple way In addition one also has the option of specifying that particular patterns will only be matched against URLs if the situation involves either a POST or a GET request

With this pattern familiar from the Rails environment one can define two different routes for identical URLs Accordingly accessing a URL with a GET request can first result in the presentation of a form however if the same URL is then accessed from a POST request this leads to the processing of the form data from the submitted form In addition one has the option of defining whether requests that match this URL pattern are to be treated as transactional requests in the Demandware sense (ie they may change or create Demandware business objects) One may also define whether a request may only be made via HTTP or only via

5

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 2: gug-doc

Index11 Hello World - How do I create a new page5

Motivation context problem scenario5Defining the URLs routes5

Routes routing6Backend controller8Templating10Helper classes12i18n internationalization12Folder structure13

12 Use case Product detail page13Motivation context problem scenario13Preconditions prior knowledge13

Demandware products14Import15GlobalData15

Implementation16Backend16Frontend17

13 Use case Category page17Motivation context problem scenario18Preconditions prior knowledge18Implementation18

Server-side implementation18Client-side implementation20

14 Use case Checkout20Motivation context problem scenario20Preconditions prior knowledge20

Functional requirements20Demandware settings20

Implementation21Gift option22Coupon codes22Personal customer data (may need registration login)22Address details (shipment billing address)23Shipping types23Payment types24Order completion24

21 Reference for CurrentMasterProduct and CurrentVariantProduct24Structure and properties25Creating objects for products26

Example 1 Creating a product with a master ID26Example 2 Creating a product with a variant ID27

2

22 Recipe Content asset with jsonContent27Motivation context problem scenario27Solution model28Implementation28Advantages28Disadvantages29Outlook29

23 Recipe Product detail page with globalData29Motivation context problem scenario29Solution model30Implementation30

24 Use case Send email30Motivation context problem scenario31Preconditions prior knowledge31Overview of steps to be completed31

a) Configuration of MVCPipes31b) Creation of a sendMailTo() helper method32c) Implementation of the SendEmail helper in the controller of the relevant page32d) Creation of an asset in Demandware Business Manager34

email_tell_a_friend asset34Integration of asset within template35

e) Creation of a business object in order to be able to validate and subsequently access data from the form35

31 Use case Frontend controller36Motivation context problem scenario36Preconditions prior knowledge37Implementation37

Creating the basic framework37The rootNode property38ready() and nodeReady()38Accessing return values from the backend controller38Sub-methods38has properties39Access to Weet URLs39Access to widgets and inits39

32 Use case Sharable widget40Motivation context problem scenario40Preconditions prior knowledge40Embedding the Sharable widget40

Creating the basic framework4033 Recipe Sharing a product page41

Motivation context problem scenario41Various solutions41

a) Facebook Like button41

3

b) FacebookTwitter share link42c) Others42

Outlook4334 Use Case Frontend JavaScript inits43

Motivation context problem scenario43Conventions43Solution model 1 Simple init (without Joose class)43Solution model 2 Complex init (with Joose class)43Implementation44Advantages44Disadvantages44Outlook44

35 Use Case Frontend JavaScript widgets45Motivation context problem scenario45Conventions45Solution model 1 Simple widgets (without Joose class)45Solution model 2 Complex widgets (with Joose class)45Implementation46Advantages46Disadvantages47Outlook47

36 Use case Video player init47Motivation context problem scenario47Preconditions prior knowledge47Embedding the video player init47

Creating the basic framework484 Recipe CSS48

Motivation context problem scenario49The use of LESS-CSS49

Client-side usage49Splitting of CSS files49CSS structure50

Conventions50Conversion for use in a live context51

5 Use case Make AMS content maintainable51Motivation context problem scenario51Creating a page in AMS51Qooxdoo window52

Template52Qooxdoo model53

Document53Node Exporter54

Export54

4

11 Hello World - How do I create a new page

This documentation is intended to show you how to create a page as well as the steps that are necessary to ensure that the desired result is provided at your chosen URL

By applying this information the reader should be capable of defining a URL implementing the logic at the appropriate place and producing a template for presenting the page

Motivation context problem scenario

Starting from scratch can be quite difficult This chapter helps with the first steps that are necessary to create a website following the same principles that apply to all Gucci shops created by SinnerSchrader The main intention here is not so much showing the various aspects and concepts of Demandware but rather to present those that have been used and are important in shops created by SinnerSchrader

Defining the URLs routes

Unlike standard Demandware implementations we will not be using the graphical pipelines Instead we have constructed an MVC framework that provides the range of options with which you will be familiar as a web developer

The graphical pipelines have a number of disadvantages First they are highly static and difficult to maintain Above all however it is also theoretically impossible to work on a pipeline with multiple developers The reason for this is that even the repositioning of a single pipelet leads to changes at various places in the XML file ndash a file in which the pipeline is ultimately saved This leads to a situation where conflicts that occur when merging before checking-in to a shared repository are very difficult ndash or impossible ndash to resolve In addition the URLs that result from the pipeline model are strictly predefined (demandwarePIPELINENAME-ACTION)

The MVC framework that has been implemented here permits the user-friendly definition of any number of URLs in the form of regular expressions Routing functionality is also provided that permits the centralized definition of URL patterns for particular functions

The end result is a powerful tool for defining any number of URL patterns in a simple way In addition one also has the option of specifying that particular patterns will only be matched against URLs if the situation involves either a POST or a GET request

With this pattern familiar from the Rails environment one can define two different routes for identical URLs Accordingly accessing a URL with a GET request can first result in the presentation of a form however if the same URL is then accessed from a POST request this leads to the processing of the form data from the submitted form In addition one has the option of defining whether requests that match this URL pattern are to be treated as transactional requests in the Demandware sense (ie they may change or create Demandware business objects) One may also define whether a request may only be made via HTTP or only via

5

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 3: gug-doc

22 Recipe Content asset with jsonContent27Motivation context problem scenario27Solution model28Implementation28Advantages28Disadvantages29Outlook29

23 Recipe Product detail page with globalData29Motivation context problem scenario29Solution model30Implementation30

24 Use case Send email30Motivation context problem scenario31Preconditions prior knowledge31Overview of steps to be completed31

a) Configuration of MVCPipes31b) Creation of a sendMailTo() helper method32c) Implementation of the SendEmail helper in the controller of the relevant page32d) Creation of an asset in Demandware Business Manager34

email_tell_a_friend asset34Integration of asset within template35

e) Creation of a business object in order to be able to validate and subsequently access data from the form35

31 Use case Frontend controller36Motivation context problem scenario36Preconditions prior knowledge37Implementation37

Creating the basic framework37The rootNode property38ready() and nodeReady()38Accessing return values from the backend controller38Sub-methods38has properties39Access to Weet URLs39Access to widgets and inits39

32 Use case Sharable widget40Motivation context problem scenario40Preconditions prior knowledge40Embedding the Sharable widget40

Creating the basic framework4033 Recipe Sharing a product page41

Motivation context problem scenario41Various solutions41

a) Facebook Like button41

3

b) FacebookTwitter share link42c) Others42

Outlook4334 Use Case Frontend JavaScript inits43

Motivation context problem scenario43Conventions43Solution model 1 Simple init (without Joose class)43Solution model 2 Complex init (with Joose class)43Implementation44Advantages44Disadvantages44Outlook44

35 Use Case Frontend JavaScript widgets45Motivation context problem scenario45Conventions45Solution model 1 Simple widgets (without Joose class)45Solution model 2 Complex widgets (with Joose class)45Implementation46Advantages46Disadvantages47Outlook47

36 Use case Video player init47Motivation context problem scenario47Preconditions prior knowledge47Embedding the video player init47

Creating the basic framework484 Recipe CSS48

Motivation context problem scenario49The use of LESS-CSS49

Client-side usage49Splitting of CSS files49CSS structure50

Conventions50Conversion for use in a live context51

5 Use case Make AMS content maintainable51Motivation context problem scenario51Creating a page in AMS51Qooxdoo window52

Template52Qooxdoo model53

Document53Node Exporter54

Export54

4

11 Hello World - How do I create a new page

This documentation is intended to show you how to create a page as well as the steps that are necessary to ensure that the desired result is provided at your chosen URL

By applying this information the reader should be capable of defining a URL implementing the logic at the appropriate place and producing a template for presenting the page

Motivation context problem scenario

Starting from scratch can be quite difficult This chapter helps with the first steps that are necessary to create a website following the same principles that apply to all Gucci shops created by SinnerSchrader The main intention here is not so much showing the various aspects and concepts of Demandware but rather to present those that have been used and are important in shops created by SinnerSchrader

Defining the URLs routes

Unlike standard Demandware implementations we will not be using the graphical pipelines Instead we have constructed an MVC framework that provides the range of options with which you will be familiar as a web developer

The graphical pipelines have a number of disadvantages First they are highly static and difficult to maintain Above all however it is also theoretically impossible to work on a pipeline with multiple developers The reason for this is that even the repositioning of a single pipelet leads to changes at various places in the XML file ndash a file in which the pipeline is ultimately saved This leads to a situation where conflicts that occur when merging before checking-in to a shared repository are very difficult ndash or impossible ndash to resolve In addition the URLs that result from the pipeline model are strictly predefined (demandwarePIPELINENAME-ACTION)

The MVC framework that has been implemented here permits the user-friendly definition of any number of URLs in the form of regular expressions Routing functionality is also provided that permits the centralized definition of URL patterns for particular functions

The end result is a powerful tool for defining any number of URL patterns in a simple way In addition one also has the option of specifying that particular patterns will only be matched against URLs if the situation involves either a POST or a GET request

With this pattern familiar from the Rails environment one can define two different routes for identical URLs Accordingly accessing a URL with a GET request can first result in the presentation of a form however if the same URL is then accessed from a POST request this leads to the processing of the form data from the submitted form In addition one has the option of defining whether requests that match this URL pattern are to be treated as transactional requests in the Demandware sense (ie they may change or create Demandware business objects) One may also define whether a request may only be made via HTTP or only via

5

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 4: gug-doc

b) FacebookTwitter share link42c) Others42

Outlook4334 Use Case Frontend JavaScript inits43

Motivation context problem scenario43Conventions43Solution model 1 Simple init (without Joose class)43Solution model 2 Complex init (with Joose class)43Implementation44Advantages44Disadvantages44Outlook44

35 Use Case Frontend JavaScript widgets45Motivation context problem scenario45Conventions45Solution model 1 Simple widgets (without Joose class)45Solution model 2 Complex widgets (with Joose class)45Implementation46Advantages46Disadvantages47Outlook47

36 Use case Video player init47Motivation context problem scenario47Preconditions prior knowledge47Embedding the video player init47

Creating the basic framework484 Recipe CSS48

Motivation context problem scenario49The use of LESS-CSS49

Client-side usage49Splitting of CSS files49CSS structure50

Conventions50Conversion for use in a live context51

5 Use case Make AMS content maintainable51Motivation context problem scenario51Creating a page in AMS51Qooxdoo window52

Template52Qooxdoo model53

Document53Node Exporter54

Export54

4

11 Hello World - How do I create a new page

This documentation is intended to show you how to create a page as well as the steps that are necessary to ensure that the desired result is provided at your chosen URL

By applying this information the reader should be capable of defining a URL implementing the logic at the appropriate place and producing a template for presenting the page

Motivation context problem scenario

Starting from scratch can be quite difficult This chapter helps with the first steps that are necessary to create a website following the same principles that apply to all Gucci shops created by SinnerSchrader The main intention here is not so much showing the various aspects and concepts of Demandware but rather to present those that have been used and are important in shops created by SinnerSchrader

Defining the URLs routes

Unlike standard Demandware implementations we will not be using the graphical pipelines Instead we have constructed an MVC framework that provides the range of options with which you will be familiar as a web developer

The graphical pipelines have a number of disadvantages First they are highly static and difficult to maintain Above all however it is also theoretically impossible to work on a pipeline with multiple developers The reason for this is that even the repositioning of a single pipelet leads to changes at various places in the XML file ndash a file in which the pipeline is ultimately saved This leads to a situation where conflicts that occur when merging before checking-in to a shared repository are very difficult ndash or impossible ndash to resolve In addition the URLs that result from the pipeline model are strictly predefined (demandwarePIPELINENAME-ACTION)

The MVC framework that has been implemented here permits the user-friendly definition of any number of URLs in the form of regular expressions Routing functionality is also provided that permits the centralized definition of URL patterns for particular functions

The end result is a powerful tool for defining any number of URL patterns in a simple way In addition one also has the option of specifying that particular patterns will only be matched against URLs if the situation involves either a POST or a GET request

With this pattern familiar from the Rails environment one can define two different routes for identical URLs Accordingly accessing a URL with a GET request can first result in the presentation of a form however if the same URL is then accessed from a POST request this leads to the processing of the form data from the submitted form In addition one has the option of defining whether requests that match this URL pattern are to be treated as transactional requests in the Demandware sense (ie they may change or create Demandware business objects) One may also define whether a request may only be made via HTTP or only via

5

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 5: gug-doc

11 Hello World - How do I create a new page

This documentation is intended to show you how to create a page as well as the steps that are necessary to ensure that the desired result is provided at your chosen URL

By applying this information the reader should be capable of defining a URL implementing the logic at the appropriate place and producing a template for presenting the page

Motivation context problem scenario

Starting from scratch can be quite difficult This chapter helps with the first steps that are necessary to create a website following the same principles that apply to all Gucci shops created by SinnerSchrader The main intention here is not so much showing the various aspects and concepts of Demandware but rather to present those that have been used and are important in shops created by SinnerSchrader

Defining the URLs routes

Unlike standard Demandware implementations we will not be using the graphical pipelines Instead we have constructed an MVC framework that provides the range of options with which you will be familiar as a web developer

The graphical pipelines have a number of disadvantages First they are highly static and difficult to maintain Above all however it is also theoretically impossible to work on a pipeline with multiple developers The reason for this is that even the repositioning of a single pipelet leads to changes at various places in the XML file ndash a file in which the pipeline is ultimately saved This leads to a situation where conflicts that occur when merging before checking-in to a shared repository are very difficult ndash or impossible ndash to resolve In addition the URLs that result from the pipeline model are strictly predefined (demandwarePIPELINENAME-ACTION)

The MVC framework that has been implemented here permits the user-friendly definition of any number of URLs in the form of regular expressions Routing functionality is also provided that permits the centralized definition of URL patterns for particular functions

The end result is a powerful tool for defining any number of URL patterns in a simple way In addition one also has the option of specifying that particular patterns will only be matched against URLs if the situation involves either a POST or a GET request

With this pattern familiar from the Rails environment one can define two different routes for identical URLs Accordingly accessing a URL with a GET request can first result in the presentation of a form however if the same URL is then accessed from a POST request this leads to the processing of the form data from the submitted form In addition one has the option of defining whether requests that match this URL pattern are to be treated as transactional requests in the Demandware sense (ie they may change or create Demandware business objects) One may also define whether a request may only be made via HTTP or only via

5

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 6: gug-doc

HTTPSSSL An automatic redirect to the corresponding protocol is supplied as standard and can ndash if desired ndash be utilized

The definition of a page within the MVC framework consists of the following steps

bull Defining the route in routedsbull Writing a method in the backend controllerbull Writing the ISML template

Routes routing

As already briefly explained routes use a queried URL to describe a particular kind of behavior and call a handler ndash in this case a class and a method of the class

Only two pieces of information are mandatory for defining a route a regular expression which describes its pattern with a queried URL plus the specification of a backend controller and corresponding controller action that is to be called Further details must only be given if additional special restrictions are to be defined (eg access is possible only via HTTPS or only POST requests are allowed)

The definition of the backend controller and the action is made using a simple string whereby controller and action are separated by a hyphen (eg Home-view) Here it is important that the name of the action is written entirely in lowercase The system then searches for a controller with the name HomeController in which the method view will be accessed

If no template is specified then the name of the template is derived automatically from the definition of the backend controller and the action In this case the system assumes that the template has the same name as the action (eg viewisml) and is located in a folder with the same name as the controller (eg templatesdefaulthomeviewisml)

The possible attributes of a route are defined in the header of the file routeds

bull handler eg Account-login combination of backend controller and methodaction to be executed separated by a dash (mandatory)

bull method POST or GET ndash if set then the route definition is applied only for POST or GET requests (optional)

bull secure if true only HTTPSSSL requests permitted (optional) depending on implementation automatic redirect to the HTTPS version of the page

bull insecure if true only HTTPnon-SSL requests permitted (optional) depending on implementation automatic redirect to the HTTP version of the page

bull transactional if true (optional) permits the alteration of Demandware business objectsbull preRunPipelets eg [LoginCustomer] (optional) list of pipelets that will be

executed before the controller method is calledbull template eg accountforgotpasswordisml (optional) here variant templates

can be specified Normally the name is derived from the name of the actionbull json if true (optional) then a special rendering template for JSON is used

Here is some sample code for a simple route definition file (routeds)

6

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 7: gug-doc

Route the app This file is the entry point for all requests Pathes are matched against the defined regexes input path String URL path input CurrentHttpParameterMap Object output controllerActionName String A Continuation Object output continuation Object A Continuation Object output pathParas Array the paras in the URL output route Object output country Object output fixedParameters Object

importScript(globalrequireds)var router = require(pipelinerouterds)requireJoose()require(gcsrvbocountryCountryds)require(gcsrvutilURLds)

Sample Route ^login(w+)$ match the path login - The regex captures will be passed as position parameters to the controller method Use the Account controller (gcsrvcontrollerAccount) with the method login Method names a lowercased before calling them handler Account-login method POST only accept post request Other possible value GET (optional) secure true only accept secure requests (optional) transactional true do transactions in requests preRunPipelets [LoginCustomer] run the LoginCustomer pipelet before the request template accountforgotpasswordisml use this template (optional default to lowercase controller namelowercase method name) json true set to true if route always returns JSON

importScript(globalpipelinerouteds)

function execute( pdict ) return routerroute(Routes pdict)

var shopPrefix = gcsrvutilURLshopPrefixvar shopPrefix = shop-[^]+var storiesPrefix = gcsrvutilURLstoriesPrefixvar pid = [w-]+var pids = [w-]+

7

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 8: gug-doc

var qty = d+var orderNo = d+var zipCode = w+var defaultLocale = dwsystemSitegetCurrent()getDefaultLocale()

first matching route wins add more routes freelyvar prefix = ^([a-z]25)([a-z-]+)var prefix = ^([a-z-_A-Z]+)

var Routes = [

prefix+grantmeaccesstosmc$ handler Access-grant everyone true

collections - looks prefix++shopPrefix+collectionslooks()$ insecure true handler Collections-looks

collections - looks - short url prefix+c()( + pid + )$ insecure true handler Collections-looks

]

Backend controller

In accordance with the MVC approach the business logic ndash ie the Model ndash is encapsulated in the business objects while the Controller assumes control and prepares the business objects necessary for the View of the respective request The template itself should therefore contain only the code that is required to display the content (MVC pattern)

Every controller is derived from the PageController class This base class contains a number of helper functions used eg to provide a standardized way of describing and providing caching tracking or other items In addition this base class also implements key MVC framework functions as well as server-side redirects Generally one needs to know nothing more than the fact that this base class represents all backend controllers

In an actual controller class one may now override the default implementations of the PageController This is useful to change the caching behavior for example In PageController caching is deactivated Here the method cacheEnabled always returns false If you now wish to change the caching behavior for the pages that are rendered via a particular controller then you can override the functions cacheEnabled cacheMinutes cacheHours and cacheVaryByPricePromotion accordingly The important fact here is that the controller

8

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 9: gug-doc

determines the particular caching behavior of the pages generated in each case The consequence of this is that depending on the situation you may need to make use of a different controller to achieve different caching behavior

Above all however here is the place you define the business logic necessary to render a page In the process the MVC framework automatically calls the method that has been defined in the route The result returned by each of these methods is a JavaScript object that will later be available in the template as a property of the variable p This is similar to the pdict entity familiar from Demandware

Here is some sample code for a simple controllerimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require_()require( gcsrvcontrollerPageControllerds )require( gcsrvboCategoryds )require( gcsrvbocontentFolderds )require( gcsrvbocontentAssetds )

Controller for stories

Module(gcsrvcontroller function (m)

Class(Content

isa gcsrvcontrollerPageController

methods

stories function (storyCnt) var folder = gcsrvbocontentFolderBaseget(stories) if(folder) return thisnotFound()

var subNavBaseFolder = gcsrvbocontentFolderBasegetSubnavRoot()

return folder folder rootFolder gcsrvbocontentFolderBasegetStoriesRoot() activeIndex storyCnt subnavFolder subNavBaseFolder pageTitle foldergetPageTitle() pageMetaDescription foldergetPageDescription() pageMetaKeywords foldergetPageKeywords() canonicalUrl thisgetHelper()to(folder) activeMainNav stellasworld

9

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 10: gug-doc

json function (id) var content = gcsrvbocontentAssetBaseget(id) if(content) throw Not Found +id

return content

cacheEnabled function () return true

cacheMinutes function () return 6024

xitiSubSite function () return 2 ))

Here you can also see three functions that have a special significance In the methods cacheEnabled cacheMinutes and cacheHours the PageController base class defines caching as deactivated and how long a page should otherwise be cached In order for caching to be activated the special controller implementation must override these values In addition you can also see the xitiSubSite function here this is used for Xiti tracking and specifies the subsite ID used to call tracking for pages that are created by this controller

Templating

The templates are standard ISML templates as familiar to any Demandware developer As already described the pdict entity from Demandware is supplemented with the variable p with which one can access the result from the controller method

Sample codeltisinclude template=utilpage_scriptismlgtltisinclude template=utilmodules gtltisdecorate template=pagetypespt_standardgtltisscriptgt var bodyclass = stories var richItem = pcontent var linkSubpages = trueltisscriptgt

ltisinclude template=contentpartialssidebar gt

10

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 11: gug-doc

ltdiv id=maingt lth3 class=h2gt$ pfoldergetDisplayName() lth3gt ltul class=catnavgt ltligtlta href=$ str(to(pfolder)) class=backgt$i18n(viewall) $ pfoldergetDisplayName() ltagtltligt ltligtltissharelink sharingclass=rt stella_overview sharingtext=$ richItemgetSharingText()text sharingwhat=$ richItemgetSharingText()what linktext=Share Page gtltligt ltulgt

ltisinclude template=contentpartialsstoryhead gt

ltisif condition=$richItemhasExtraImages()gt ltdiv class=imagescol2gt ltisloop items=$ richItemgetExtraImages() var=imagegt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdiv class=facongt ltisifgt ltimg src=$ html(imageurl) alt= gt

ltisif condition=$ imagepid ampamp imagepidlength gt 0 || imagezoomgt ltul class=floatactions js_actionsgt ltisif condition=$ imagepid ampamp imagepidlength gt 0gt ltli data-productid=$ imagepidjoin() gtlta href=$ javascript class=info js_viewInfogtView Infoltagtltligt ltisifgt ltisif condition=$imagezoomgt ltli data-zoomurl=$ imagezoom gtlta href=$ javascript class=zoom js_zoomgt$i18n(zoom)ltagtltligt ltisifgt ltulgt ltisifgt ltisif condition=$imagepid ampamp imagepidlength gt 0 || imagezoomgt ltdivgt ltisifgt ltisloopgt ltdivgt ltisifgt

ltdiv class=relatedgt ltisif condition=$ prelatedContent ampamp prelatedContentlength gt 0 gt ltdiv class=archivegt lth3 class=h5gt$i18n(seemore)lth3gt ltulgt ltisloop items=$ prelatedContent var=col status=statusgt ltisloop items=$ col var=cgt ltisinclude template=contentpartialsbox_archiveisml gt ltisloopgt

11

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 12: gug-doc

ltisloopgt ltulgt ltdivgt ltisifgt ltdivgt ltdivgt

ltisinclude url=$ URLUtilsurl(MVC-Dispatch path str(to(sharingsharing))) gtltisdecorategt

Within the templates the Demandware decorator approach is used This means that a set of page type templates (eg pt_standard) are available These contain the basic outer structure for a page (basic HTML structure with HEAD and BODY area plus navigational elements) This provides a convenient way of encapsulating and reusing repetitive HTML code The inner template which utilizes the page type template must also include the decorator tag (eg ltisdecorate template=pagetypespt_standardgt) The decorator template itself contains the ltisreplacegt tag at the position at which the template code is then included (see Demandware documentation)

Helper classes

The framework provides a great many helper methods which can ndash as just one example ndash be used for correctly outputting prices etc To ensure that the backend controller is executed the variable p is filled and the remaining helper classes are available the very first action in a template must be to include the page_scripts template (ltisinclude template=utilpage_scriptisml gt) After this the developer then has access to all of the utility functions

i18n internationalization

Although internationalization (or i18n for short) covers a number of different aspects its primary role is to provide pages in multiple languages To ensure this can be achieved one should never include language-specific text in a template or controller directly Instead of this one should use the Demandware property mechanism As familiar from languages such as Java this permits the definition of entities known as property files which assign the actual language-specific texts to unique keys Since Demandware loads all property files automatically this means you always have access to the keys of all property files

Instead of using the Resource class from Demandware you should utilize the i18n method provided by the framework This offers a few extensions that among other things permit the utilization of property file content in frontend JavaScript functions

Sample property file (accountproperties)accountprofilecompletehead=Complete Your Profileaccountprofilecompletepromo=What is thisaccountprofilecompletebuttonsnext=Next

12

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 13: gug-doc

accountprofilecompletebuttonsor=oraccountprofilecompletebuttonsskip=Skip this stepaccountprofilewelcome=Welcome on 0 dear 1

Within a template or controller you can then apply your chosen text via the i18n method In a template for example this may look as follows

$i18n(accountprofilecompletepromo)

As familiar from Java the use of placeholders within a resource definition is also possible$i18n(accountprofilewelcome Stella McCartney Tim)

The placeholders are numbered sequentially starting with 0 and passed to the method as additional parameters

Folder structure

Here we give a brief explanation of where these various files are to be found within a project

12 Use case Product detail page

This use case provides knowledge of

bull Which data is required in order to display a productbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

This use case covers the following items from the list of topics to be documented

Motivation context problem scenario

Products are to be displayed on a page The page is to display items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

In order to be displayed products must first exist within the system

The following two sections show how products are modeled within Demandware ndash and which aspects of this model we utilize ndash and how the data that describes a product is brought into the Demandware system We assume prior knowledge of any details that are part of the Demandware documentation and which are not given special treatment in this document

13

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 14: gug-doc

A third section presents a short overview of the GlobalData mechanism which is used to transport data from the backend to the frontend GlobalData is presented in more detail in a dedicated chapter (see 32)

Demandware products

There are a number of types of products We use master products and the variations assigned to master products (Rarely also product sets but that topic exceeds the scope of this use case) Products are assigned to categories Categories are used to create the menu system on the shop pages Products and categories are part of the Catalog (For products and categories see also the Demandware documentation)

There are a few conventions that should be observed in connection with Catalog data The observation of these conventions can be assumed for a number of components that we have developed These conventions affect the notation of IDs the colors of products and the assignment of variations to products

bull IDs The ID of a master product is a combination of style and material Often a combined ID is output consisting of style material and color The IDs for variants do not correspond to this schema

bull Colors The color of a product is saved within the product at multiple locations The Colour Code attribute stores the color code of the product This is the exact same code that can also be output as a component of the ID (see above) One example would be the color code 4100 (Notte) The Variant RGB Colour attribute stores a color value that corresponds to the color of the variation or the product Products with a number of color codes should also have different values for the Variant RGB Colour attribute An example of a value for this attribute would be 7D242A (Carmine) The RGB Colour Code attribute stores a color value for the product taken from a less differentiated scale This value is used to organize products in terms of color pickers Products with different (similar) values for the Variant RGB Colour attribute may have the same value here The total number of possible values for this attribute should not exceed the number that can be shown simultaneously in the color pickers An example of a value for this attribute would be 662D36 (Red)

bull Variant assignment Variants are assigned to the Master products This takes place via one or both of the attributes Size and Colour The values used for Colour correspond to the values in the attribute Colour Code When assigning variants to a master product it is important that no variant is assigned via an attribute with the value -NONE- Master products with variants function properly only if all variants have been assigned to the master product via specific values in the attributes

In addition to data from the product catalog there are other types of data that also displayed on product pages Examples of these types of data include prices availability or images

bull The prices for the products are stored in pricebooks This is a standard Demandware feature

14

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 15: gug-doc

bull The availability of products is mapped to custom objects Demandwares inventory feature was not suited for implementing the requirements These custom objects are stored using a combined ID made up of the product ID and the warehouse ID The warehouse ID is specified for each website individually in the settings (under Global Preferences Custom Preferences Gucci using the storeCode key) Access to availability is provided via the API for the product classes (see below)

bull Images for the products are stored within a CDN such as Limelight The images attribute for the product is used to define which images are available at which resolutions An example of a valid value for this attribute would be 1200x768[AB]90x90[AB]52x52[A] This entry is created by a script that searches across the CDN for all product images (see below) In the product classes a path is implemented at which the images on the CDN can be located This path is used both to generate paths to specific images and in addition to determine the images that are actually available on the CDN Access to image paths is provided via the API for the product classes (see below)

Import

The data items that make up a product are imported separately

bull Catalog The Catalog is imported manually using Demandwares import functionbull Prices A Scheduled Job (ImportPricebooks) determines whether new pricebook

files are present in the import folder and if so imports the new pricebook using Demandwares import pipeline

bull Stocks A Scheduled Job (ImportStocks) determines whether new stock files are present in the import folder and if so imports the new stock data using a custom import script developed in-house This script creates the custom objects mentioned above for product availability

bull Images Images are initially copied to the CDN using the naming convention that is also implemented in the CDN path in the product classes A script is then executed to check the images (ImportImages) this searches across the CDN for all product images and creates the correct entries in the images attribute (see above)

GlobalData

Developers have a number of server-side methods available for storing arbitrary kinds of data in a JavaScript hash these data items are later made available in the client as JavaScript objects The ProductController adds all of the products discovered during the processing of the current request to the GlobalData hash using the method add2GlobalData() that is provided by BaseHelper Finally this hash is then serialized into the HTML document using the method printGlobalData() the method printData() does not collect data first but outputs data directly

15

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 16: gug-doc

In the frontend the previously serialized data is re-read compiled into JavaScript data items and then provided to the client by means of a GlobalData structure The methods gcglobalData() and gcglobalData$() are used here

A detailed description of the possibilities provided by GlobalData is given in a dedicated chapter (see 23)

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system ndash then a page for displaying the products can be implemented The following sections list the steps necessary to do so

Backend

The construction of a page with product details essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case (see 11) In addition to this the following aspects specific to product detail pages must be considered

The route must be created in a way that ensures the product name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Product controller and the view action

prefix+shop-[^]+[^_]_([w-]+)html$ handler Product-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a product as a parameter The action creates an instance of the requested product reads data items modifies these as required and then ultimately passes the product or the product data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Product isa gcsrvcontrollerPageController methods view function ( pid ) var product = gcsrvboproductgetProduct(pid) var h1 = productgetCurrent()getName() return product product h1 h1

The products can be created using the gcsrvboproductgetProduct(pid) function For the various kinds of products (simple product product set master product with variants

16

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 17: gug-doc

etc) an instance of the corresponding classes is thus created in each case Figure 1 shows the class diagram for the most important classes involved in products

The product classes encapsulate product properties and also provide a wide variety of helpful functions such as for example getStockInfo() for reading availabilities getDimensions() for reading and formatting the product size or getShortURL() for generating a short URL for links to the product

In the template the data passed from the action can then be output The following piece of code uses a few sample lines from a template for displaying product details to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var product = pproduct var data = pdata var current = productgetCurrent()ltisscriptgt

lth2 class=h5gt$ currentgetShortDescription() lth2gt

$ productImageTag(current 470x550 standard null pdi true)

17

Figure 1 Class diagram

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 18: gug-doc

Here the product image is output using the helper function productImageTag() from the product helper

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism (described briefly above) thus ensuring they can be extracted from here by the frontend

Frontend

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the product page this means that an object of a JavaScript product class also exists in the frontend This object can then be used in the client-side JavaScript Some examples of possible usage scenarios include the Selector with which product variants can be selected or the dynamic replacement of images Separate documentation provides more detailed information about the Selector and JavaScript for handling product images (see 34 and 35)

13 Use case Category page

This use case provides knowledge of

bull Which data is required in order to display a category with productsbull How is this data brought into Demandwarebull How is this data extracted back out of Demandwarebull How is this data displayed

Motivation context problem scenario

A category is to be displayed on a page The page is to display a list with products The individual products should be displayed with items of product information such as name description images price availability etc Gucci projects implemented to date have used a standardized procedure for the technical realization of such requirements The solution presented here should not only follow this standardized procedure but also convey it to the reader in a way that makes it possible to implement further projects or changes to existing projects in accordance with this procedure

Preconditions prior knowledge

The preconditions and prior knowledge required for this use case are exactly the same as those for the product detail page For details please consult the documentation on the product detail page (see 12)

18

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 19: gug-doc

Implementation

Once the preconditions have been satisfied ndash in particular that products have been created in the system (see 12) ndash then a page for displaying the category can be implemented The following sections list the steps necessary to do so

Server-side implementation

The construction of a page with a product category andor a list of products essentially involves the same steps as constructing any other kind of page The construction of a simple page is described in the Hello World use case In addition to this the following aspects specific to category pages must be considered

The route must be created in a way that ensures the category name or the ID can be extracted from the URL called The following example extracts the ID from the URL and passes this to the Category controller and the view action

prefix+shop-[^]+()$ handler Category-view

The controller must have an action ndash view in the example shown above ndash that accepts a unique ID from a category as a parameter The action creates an object of the requested category reads the data items modifies any of these as required and then ultimately passes the category or the category data to the template The sample code below shows this kind of minimal action

Module(gcsrvcontroller function (m) Class(Category isa gcsrvcontrollerPageController methods view function ( categoryPath ) var category = gcsrvboCategoryfromCategoryPath(categoryPath) return product product

The categories can be created using the gcsrvboCategoryfromCategoryPath(categoryPath) For categories then an object of the Category class is created which provides a number of useful functions that can be utilized in the template or the controller for example getOnlineSubCategories() or getOnlineProducts() Figure 2 shows the class diagram for the most important classes involved in categories

19

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 20: gug-doc

In the template the data passed from the action can be output The following piece of code uses a few sample lines from a template for displaying categories to show how the objects are accessed from the action how functions are called on these objects and how the various kinds of data can then be output

ltisscriptgt var category = pcategory var mainCategory = pcategorygetMainCategory() var subCategories = isSubBottomCategoryi categorygetParent() category var directProducts = categorygetOnlineProducts()ltisscriptgt

lth2 class=h1gt$ isSubBottomCategory categorygetParent()getHeadline() categorygetHeadline() lth2gt

ltisloop items=$ subCategoriesgetOnlineSubCategories() var=cat status=statusgt ltisloopgt

ltisloop items=$ directProducts var=product status=statusgt

20

Figure 2 Class diagram

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 21: gug-doc

ltisloopgt

Appropriate functions include in particular the functions for reading the subcategories (getOnlineSubCategories) and the functions for reading the categorys products (getOnlineProducts)

The data for the individual products is then treated in the exact same way as for a product detail page The use case for creating a product detail page (see 12) describes this in more detail

The product controller inherits from PageController PageController ensures that key pieces of information are passed from the backend to the frontend Pieces of product information are written to HTML using the keyword Styles via the GlobalData mechanism thus ensuring they can be extracted again from here by the frontend GlobalData is described in more detail in its own chapter (see 32)

Client-side implementation

In the frontend the data written via GlobalData is extracted again and then transformed into JavaScript objects For the category page this means that an instance of a JavaScript category class also exists in the frontend This object can then be used in the client-side JavaScript

14 Use case Checkout

This use case provides knowledge of

bull Sample solutions for typical modifications to the basketbull Transforming the basket into an order

Motivation context problem scenario

The checkout process is one of the core elements in the shop area It covers the final adjustments made to elements in the basket plus the entry of customer shipping and payment details

Preconditions prior knowledge

Functional requirements

For the checkout process to be executed appropriately it is necessary for one or more products to be located in the basket

Demandware settings

The following steps assume several Demandware settings have been made beforehand These include

bull Configuration of taxes

21

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 22: gug-doc

bull Creation of shipping typesbull Payment typesbull Coupon codes (optional)

Implementation

The checkout is based on an instance of the Basket business object This is created immediately the customer places the first product in the shopping basket and persists until the entire checkout process has been completed

The Basket class provides a number of methods for accessing the included Demandware object Depending on the use case different strategies will be needed to enrich the basket with information In some cases it is enough to set the attributes by making simple calls to the respective functions of the DW object in other cases pipelines may in fact need to be used in order to extract or write the attributes

As the first step in developing the checkout process we require a corresponding server-side controller This should be stored within the Cartridge in scriptsgcsrvcontroller The exact allocation of tasks for the required actions depends on the functional setup of the checkout in question As a rule dedicated routes are created for the individual steps within which the basket is modified On the one hand a route with a GET route for displaying the form that is to submit the data on the other a POST route for processing the data after it has been submitted

Since sensitive data is submitted during the checkout process the secure attribute should be set in all routes in order to force an encrypted connection Since the basket can only be requested with the help of a pipeline this pipeline must be called before each controller action As examples of the two related routes for adding a shipping address consider the following (extract from the routeds file)

Addressformular anzeigenprefix+checkoutaddressform$ method GET secure true handler Checkout-show_addressform template checkoutaddressformisml preRunPipelets [GetBasket]

Addressformular verarbeitenprefix+checkoutaddressform$ method POST secure true handler Checkout-handle_addressform preRunPipelets [GetBasket]

In order to ensure the basket is then available in each controller action this item should be set in the runBefore function that is executed before each action

Initialisierung der basket-Propertyoverride

22

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 23: gug-doc

initialize function() thisrunBefore(function () thisbasket = gcsrvboorderBasketget() ) thisSUPER()

Gift option

In Demandware information about the gift option is maintained in the Shipment object This in turn is linked directly to the basket Demandware supports multiple shipment addresses for one order However since this feature has not been used to date one may as a rule access the default shipment By using the Shipment object one can then set or extract the values for the gift option (Boolean) and the gift message (String) as appropriate

Coupon codes

To apply a coupon code to the shopping basket the AddCouponToBasket2 pipeline is called before executing the controller action Following this call the values returned by the pipeline must be analyzed within the controller action First you will need to check whether a CouponLineItem could be found using the key second you must check whether it was possible to apply the coupon to the basket If no matching coupon was found then you have the option of using the CouponStatus in order to determine the reason

Personal customer data (may need registration login)

As a rule it should be possible to assign an order to a customer Accordingly you will also need to enter customer-specific details such as firstlast name for example and an email address If you utilize Demandware user management for this purpose then the customer details ndash unlike address and payment details ndash will not initially be stored in the basket object In this case it would also make sense to use the runBefore function to load the Customer in all controller actions

Initialisierung der customer-Propertyoverride initialize function() thisrunBefore(function () thiscustomer = gcsrvbocustomerCustomerget() ) thisSUPER()

23

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 24: gug-doc

As an alternative you have the option of using custom attributes to store individual customer details directly to the basket

Address details (shipment billing address)

The shipment and billing address are mandatory items for the checkout The shipment address is stored to a Shipment object Demandware supports the option of adding multiple shipments to the basket However no use has been made of this functionality to date Accordingly you may simply utilize the defaultShipment The Basket offers the methods getShippingAddress and getBillingAddress each of which returns an object of an Address class The actual class of the address object returned can depend on the region that is currently selected As soon as the corresponding addresses are requested these are also created at the Demandware basket as required

To be able to display an address form the controller action must supply an address object that can accept the values of the individual form fields

For processing following the submission of the form the helper is used to fill the address object with the form data Following this the address should also then be validated using the method defined in its class (eg via Cybersource) If the data submitted is accepted then the next step can be initiated However if an error occurs the address form must be displayed again with the corresponding error messages In simplified form the two controller actions for displaying and processing an address form could be written as follows

Action fuumlr das Anzeigen eines Adressformularsshow_addressform function() return shippingAddress thisbasketgetShippingAddress() shippingAddressErrors gcsrvflash(shippingAddressErrors)

Action fuumlr die Verarbeitung eines Adressformularshandle_addressform function() var shippingAddress = thisbasketgetShippingAddress()

thisgetHelper()formUpdateObject(shippingAddress shippingAddress)

if (shippingaddressisValid() ampamp shippingaddressisCybersourceValid()) thisredirectTo(checkoutpaymentform) else gcsrvflash(shippingAddressErrors shippingAddressgetErrors()) thisredirectTo(checkoutaddressform)

24

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 25: gug-doc

Shipping types

In Demandware a shipping type is defined per Shipment Since only a single Shipment has previously been considered per order the function currently available from the Basket is changeDefaultShippingMethod This will pass a ShippingMethod that can be requested via the function getShippingMethod Demandware provides the ShippingMgr for the identification of all shipping types that have been entered within the Business Manager

Payment types

For processing the payment type for the checkout the Basket offers functions that are similar to those used for address processing Accordingly the function getPayment can be used to request a Payment object which is created beforehand as required This Payment object can also be filled by the helper and is then itself responsible for the validation

Order completion

Once all pieces of information have been stored to the Basket object the CreateOrder pipeline can then be called This creates an Order object from the basket Once the pipeline has completed you can then access the order to perform further manipulations on it For example you can then add any additional customer details In addition it is important that you update the stock details for the products contained The following code snippet displays possible actions following the creation of the order

Aufruf der Pipeline CreateOrderthisaddContinuation([CreateOrder] function() var order = gcsrvboorderOrderget()

thisredirectTo(checkoutconfirmation + ordergetOrderNo())

orderinitializeFromBasket(thisbasket) orderapplyStockAvailabilities() ordersetCustomerOrderReference(thiscustomergetID()) orderprepareForExport()

In this context the export status of the order is also important Within the code this should be set to READY_TO_EXPORT as soon as the order is ready for exporting Only then will the order be available for exporting as XML by the recurring Export job

21 Reference for CurrentMasterProduct and CurrentVariantProduct

The two classes CurrentMasterProduct and CurrentVariantProduct extend the product model familiar from entities such as the Product ProductBase

25

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 26: gug-doc

MasterProduct und VariantProduct classes Unlike elsewhere in the product model this extension does not occur by inheritance but in accordance with the Decorator design pattern

This mechanism is comparatively complex and is therefore presented in a dedicated chapter

If we consider the product model then we may as a rule consider both CurrentMasterProduct and CurrentVariantProduct as abstractions since these classes support the same interface as the classes thereby decorated For most work involving the product model it is not necessary for us to consider CurrentMasterProduct and CurrentVariantProduct directly

Here we describe an idealized state The actual implementation may show minor deviations from this state

Structure and properties

Figure 3 shows the components involved plus the structure of their mutual interrelationships

Relevant properties and relationships for the classes and objects involved are as follows

26

Figure 3 Class diagram

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 27: gug-doc

bull The factory() method in ProductManager returns a CurrentMasterProduct In most cases factory() is called by the $() method from requireds with which Demandware objects are transformed into objects of classes from the product model

bull For each master product only a single object of the MasterProduct class is created If there are multiple different variants of the same master on a page only exactly one object of the MasterProduct class is created for these Although the master product knows about all the variants it does not know which variant is currently selected

bull In CurrentMasterProduct the MasterProduct class is extended with the getCurrent() method The getCurrent method returns the currently-selected variant as an object of the CurrentVariantProduct class The getVariants() method returns all variants as objects of the CurrentVariantProduct class

bull Although a VariantProduct knows about the master it does not know which variant is currently selected With the getMaster() method a VariantProduct can return only a MasterProduct ndash not a CurrentMasterProduct

bull CurrentVariantProduct extends VariantProduct and overrides getMaster() so as to return a CurrentMasterProduct in this way the currently-selected variant can thus be retained

bull In addition CurrentVariantProduct also provides the method getCurrent() which is an abbreviated form of getMaster()getCurrent()

bull CurrentMasterProduct delegates all calls to unknown methods to the internal object of the MasterProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull CurrentVariantProduct delegates all calls to unknown methods to the internal object of the VariantProduct class passing __noSuchMethod__ Methods whose existence is checked (duck typing eg toJSON()) must be implemented explicitly and handle delegation to the internal object themselves

bull The objects with which we work are therefore always objects of the CurrentVariantProduct or CurrentMasterProduct class

Creating objects for products

Figure 4 shows a sequence diagram for the creation of a product when taking the classes CurrentVariantProduct and CurrentMasterProduct into account

27

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 28: gug-doc

The following examples clarify the interplay between the participating classes and objects

Example 1 Creating a product with a master ID

The following example shows the key steps taken when creating a product from the starting point of a master product ID As a rule products are created from the starting point of a variant ID This will be shown in the next example The approach taken using a master ID is slightly simpler and is therefore shown first

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of the MasterProduct class with the properties of the selected product

2 The variants of the master product are initially each created as objects of the VariantProduct class Following this they are each encapsulated in an object of the CurrentVariantProduct class

3 The references to the variants (CurrentVariantProduct) are stored in the object of the CurrentMasterProduct class The getVariants() method in the object of the CurrentMasterProduct class returns precisely these variants

4 Since no variant is specified the default variant is created and set and stored in the object of the CurrentMasterProduct class The getCurrent() method in the object of the CurrentMasterProduct class then returns precisely this variant

28

Figure 4 Sequence diagram

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 29: gug-doc

Example 2 Creating a product with a variant ID

The following example shows the key steps taken when creating a product from the starting point of a product variant ID As a rule products are created in this exact way

Essentially the creation of the product from the starting point of a variant ID is the same as the product creation in the preceding example The following differences apply

1 The factory(masterId) method in ProductManager creates an object of the CurrentMasterProduct class Referenced in here is an object of theMasterProduct` class with the properties of the master product that belongs to the selected variant

2 Since a variant is specified the object of the CurrentVariantProduct class for precisely this variant is stored as the selected variant in the object of the CurrentMasterProduct class

22 Recipe Content asset with jsonContent

This recipe provides knowledge of

bull Optimizing the structural clarity of objects (re custom attributes) (eg products categories etc)

bull Improving the flexibility of custom attributes for objects

Motivation context problem scenario

Demandware objects such as categories products preferences and also custom objects must be extended with custom attributes in accordance with the requirements for the system If these requirements change or are implemented step-by-step during the development process the custom attributes for the objects will change In the objects attributes start to pile up over time the objects become increasingly cluttered due to the number of attributes Of the attributes available for objects none are used all of the time Reasons for unused attributes may be With multiple sites attributes are used only site-specifically but were not created in a site-specific way Attributes will be replaced by others but the old ones cannot be removed immediately ndash and are then never removed Attributes may exist such that all may be used only potentially ndash and as a rule only a few are actually used (eg Image-1 Image-2 Image-n) Objects can be deployed in a variety of different contexts which each require their own set of attributes Only the common members of these attribute sets can always be used Attributes required for each of the other contexts remain unused

A simple approach to ensuring objects are less cluttered is to store attributes externally in implicitly associated objects ndash ie generally in content assets As an example we have a product for which all images can be displayed that are present in content assets which are present in a library folder which has the same ID as the product This approach generates a set of new problems

29

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 30: gug-doc

bull The solutions are not robust and are strongly dependent on observing the particular convention selected

bull Depending on the use case this may involve different sets of conventions (for product images teasers on category pages)

bull An arbitrary number of different competing conventions may exist The lack of clarity in the object is not resolved ndash but only outsourced

Solution model

We select the following model for resolving the problem described above

Instead of saving data items belonging to an object in a set of dedicated custom attributes they are stored in a single attribute within a JSON structure

Implementation

In the simplest case the data items are stored in a JSON structure directly on the object itself in a single attribute (jsonContent)

For products and categories it may be necessary to continue to store data in associated content assets Content assets are site-specific whereas this need not be true of products and categories In order to store site-specific content on site-independent objects this content is stored in content assets that are implicitly associated with the object by convention Due to the 1-to-1 relationship between object and content asset this at least enables us to reduce the problems with associated content mentioned above

Encapsulation provision of an interface to product category and content asset

The current implementation provides the functions getJsonContent() and getJsonData() These functions return the content in their JSON structure The content is loaded either from the object itself or from associated content assets as required

Two other functions ndash createJsonData() and augmentJsonData() ndash are also called from the functions mentioned above as required The createJsonData() function creates an empty structure This function can be replaced or overridden in order to create more complex structures The default is an empty object The function augmentJsonData() is used to extend the content in the JSON structure before it is returned This function can be replaced or overridden with references one use would be to replace IDs in JSON with objects The default is to return the object unchanged

Advantages

The solution model described above has the following advantages

bull Product attributes remain unclutteredbull Flexibility is ensured by the ability to change or extend the JSON structure while keeping

product attributes unchanged

30

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 31: gug-doc

bull Cross-site uniform attributes may exist in the objects while simultaneously a variety of site-specific content is present in the JSON structures

bull Simplification of data import from external sources (see eg AMS) Import always occurs into the exact same selection of attributes ndash and the jsonContent attribute in particular

bull JSON is simpler and less cluttered than eg XML etc JSON can be used directly within JavaScript

Disadvantages

The above solution model has the following disadvantagesdoes not resolve the following problems

bull In the Business Manager it is almost impossible to change objects with content held in jsonContent (at least the content in jsonContent) When editing this content no selection dialogs are available for images ndash or similar aids that otherwise facilitate the editing of attributes

bull The problem with implicitly-associated content remains essentially unresolvedbull There are limitations to content search functionality The search does not distinguish

between the content itself and the keys of the JSON structure

Outlook

Together with its implementation the solution model presented here can achieve significant improvements to the structural clarity of custom attributes in objects Only this approach makes the deployment of external tools for editing content (AMS) into a relatively simple process

23 Recipe Product detail page with globalData

This recipe provides knowledge of

bull Transferring JavaScript objects and data from the backend to the frontend for deployment on the client side

bull A mechanism to transport objects without explicitly transforming them into character strings and without a separate AJAX call

bull Use of the mechanism on a Demandware page

bull Use of the mechanism in the client (browser)

Motivation context problem scenario

As a rule any web page consists of server-side logic and client-side logic While the latter must be supplied with data it does not have a direct link to the Demandware data source For this purpose the required data can be requested from the server via an additional AJAX call or embedded in the HTML webpage during the initial loading process The latter is especially

31

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 32: gug-doc

useful for data created as a result of complex calculations A subsequent AJAX call would repeat the execution of these calculations

Solution model

The globalData methods offer a simple solution without explicit embedding ndash via the data attribute for DOM elements for example ndash and without a repeat explicit extraction from the HTML

Implementation

To achieve this techniques are available in the active controller for writing to a JavaScript object In the templates this object is then serialized to an HTML comment and following the delivery of the HTML document transformed back into a globalData object within the client In the backend the following properties apply

bull Each controller inherits the globalData object from PageController with the properties data and events

bull data is itself a hash and its keyvalue pairs will be serialized later to JSONbull events can be enriched with functions that are executed at the point in time at which

serialization takes place Since events is itself a hash keys that are already present may be overwritten

bull In the template the printGlobalData() helper method is called this takes the values stored in globalData serializes them and writes them to the HTML output stream to be generated These values then later appear in an HTML comment in the HTML document delivered to the client

bull The base helper supplies the addGlobalData(key value) method for writing to data

bull The base helper supplies the add2GlobalData( function() ) method for writing to events

In the frontend gc is available and already contains all values in JavaScript format

Accordingly no explicit de-serialisation must be carried out If multiple globalData comments occur in the HTML document or if additional HTML documents are loaded subsequently via AJAX then the data items they contain are also imported to gc and any data pairs already present may be overwritten Access to the values in gc is achieved by using the gcglobalData( key ) and gcglobalData$( key ) functions The first function throws an exception if no key entry is present the second function returns null if a key entry is missing

24 Use case Send email

This use case provides knowledge of

32

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 33: gug-doc

bull How the logic is implemented for sending an emailbull How an email is sent with data from a formbull How a template for the email can be utilizedbull The required format for the template to use in an HTML email

This use case covers the following items from the list of topics to be documented

bull Sending an HTML email with data from a form

Motivation context problem scenario

This use case shows how an email can be sent with data from a form A detailed description shows where the implementation needs to be carried out at for relevant points in the source code

Preconditions prior knowledge

The reader should be familiar with the underlying structure of the project Topics such as business objects controllers ISML templates assets in Demandware Business Manager and pipelines should already be understood

Overview of steps to be completed

Here we provide a short overview of the steps that are required in order to complete sending an email

a) Configuration of MVCPipesb) Creation of a sendMailTo() helper methodc) Implementation of the SendEmail helper in the controller of the relevant paged) Creation of an asset in Demandware Business Managere) Creation of a business object in order to be able to validate and subsequently access data

from the form

The following sections discuss the individual steps in more detail

a) Configuration of MVCPipes

Demandware permits access to the internal business objects via pipelines and pipelets In Demandware UX Studio the Pipeline Editor is used to create individual pipelines and pipelets These items of information are stored in XML files A SendMail pipelet is provided out of the box This pipelet is created in the Editor in the familiar way The following properties and the corresponding values used in the example are envisaged for email dispatch

bull LocaleID - nullbull MailBCC - continuationdataemail_bccbull MailCC - continuationdataemail_ccbull MailFrom - continuationdataemail_frombull MailSubject - continuationdataemail_subjectbull MailTemplate - continuationdataemail_template

33

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 34: gug-doc

bull MailTo - continuationdataemail_to

Accordingly the values must be assigned as shown above

b) Creation of a sendMailTo() helper method

See helloWorld for details of the directory structure of the project In the directorycartridgescriptsglobalgcsrvhelper

you will find the file Baseds A sendMailTo() method is created in this class The contents may look as follows

sendMailTo function(from to asset bo anothermail bcc fn)

thiscontrolleraddContinuation([SendEmail] function () if (fn) return fn() )

if(asset) throw no email-asset found to send a mail

return email_to to email_from from email_subject thisrenderAsset(assetgetHeadline() bo) email_template mailsmtpmailisml email_bcc bcc email_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo) anothermail anothermail

When this method is called a SendEmail continuation is initially placed onto a stack to be processed but not yet executed The signature of the sendMailTo() method permits a function as its last parameter This is executed once the continuation ndash here SendEmail ndash has been executed

First a check is now made to see whether an asset exists If not an exception is thrown The function returns an object containing all of the data items relevant to the pipelet This object is made available within the pipeline under continuationdata This is the exact point in time at which the continuation or pipeline that was placed on stack is executed and the email is sent

34

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 35: gug-doc

c) Implementation of the SendEmail helper in the controller of the relevant page

For our example we take a form which is labeled as Tell a Friend on the website As the name suggests the idea is for a visitor to use the form to tell a friend about the web page The first step is to create a controller This can be found at

cartridgescriptsgcsrvcontrollerSharingds

and its contents are as followsimportPackage( dwsystem )importPackage( dwutil )importScript(globalrequireds)requireJoose()require( gcsrvcontrollerPageControllerds )require( gcsrvbocontentAssetds )require( gcsrvbosharingTellAFriendds )

Module(gcsrvcontroller function (m) Class(Sharing isa gcsrvcontrollerPageController

methods tell_a_friend function () var obj = new gcsrvbosharingTellAFriend() var helper = thisgetHelper() var asset = gcsrvbocontentAssetgetActiveAssetByType(emailfriend) var from = objsenderEmail to = objrecipientEmail data = senderName objsenderName message objmessage sharedLink objurl siteUrl helperstr(helperto()absolute()) customerCare mailto+helperi18n(globalcontactcustomerCareEmail) bcc = (objsendEmailCopy === true) objsenderEmail undefined

return helpersendMailTo(from to asset data undefined bcc)

tell_a_friend_form function() return ))

Within the routing in

35

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 36: gug-doc

cartridgescriptspiplinesrouteds

there is a POST and a GET routeprefix+sharingtell_a_friend$ method POST handler Sharing-tell_a_friend template partialslightboxtellafriend_successisml

prefix+sharingtell_a_friend$ method GET handler Sharing-tell_a_friend_form template partialslightboxtellafriendisml

Here we can see that the tell_a_friend() method is called for a POST request and the tell_a_friend_form() method is called for a GET request

In the tell_a_friend method (POST) the first step taken is to create an object of the TellAFriend business object class (see 24e) This object contains the form data Furthermore the HTML markup from the Demandware Business Manager is assigned to the asset variable (see 24d) Finally all of the relevant data is passed to the sendMailTo() method and the email is sent ndash assuming that no errors have occurred

d) Creation of an asset in Demandware Business Manager

email_tell_a_friend asset

In the Demandware Business Manager a configuration asset is created from the AMS in the Site gt Content area (see AMS)

36

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 37: gug-doc

Within this asset and under Rich Content (JSON) you will find the JSON object with all of the relevant entries ndash and also the entry

emailfriendemail_tell_a_friend

The emailfriend entry refers to another asset named email_tell_a_friend In this asset you will find the HTML markup that is then included in the template smtpmailisml as described below

37

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 38: gug-doc

ltpgtHello from our websiteltpgt

ltpgtlt= bosenderName gt would like to share this information with you from lta href=lt= bositeUrl gtgtsitecomltagtltpgt

38

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 39: gug-doc

ltpgtlt= bomessage gtltpgt

ltpgtlt= bosharedLink gtltpgt

This data was passed to the sendMailTo() method by the data object (see 3) Within the asset access is now possible via the bovariable

Integration of asset within template

In the SendMailTo() helper method a template and the content from the asset is specified in the object to be returned

email_template mailsmtpmailismlemail_body thisrenderAsset(assetgetBodyMarkup()getMarkup() bo)

The email_body is then assigned the markup that was extracted using the asset object previously specified from the Business Manager

email_template is the framework template that is being used here Fully-specified HTML markup is integrated within this template Naturally inline JavaScript can also be used here in the standard way The content of the asset must be included within the template Here it is important that the HTML markup is kept unchanged and is not encoded Accordingly the ltisprintgt tag is used and the encoding=off attribute is set

ltisprint value=$ pemail_body encoding=off gt

In this way the asset from the Business Manager is integrated within the template The email is complete

e) Creation of a business object in order to be able to validate and subsequently access data from the form

Here it is appropriate to create a business object that encapsulates the validation and the access to the form data In the present example an object of this kind with the name TellAFriend has been created This can be found at

cartridgescriptsgcbosharing

Which can also be derived by callingvar obj = new gcsrvbosharingTellAFriend()

within the Sharingds controller The content of the class is as followsimportPackage( dwcustomer )importScript(globalrequireds)requireJoose()require(gcsrvboBusinessObjectds)require_()

Module(gcsrvbosharing function (m) Class(TellAFriend isa gcsrvboBusinessObject

has

39

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 40: gug-doc

senderName is rw senderEmail is rw recipientName is rw recipientEmail is rw message is rw sendEmailCopy is rw url is rw

validations senderName simple [required] senderEmail simple [required email] recipientName simple [required] recipientEmail simple [required email] ))

The class has a relatively simple structure By using Joose and initially setting individual variables such as senderName these variables can be accessed very simply in the controller by the use of getters and setters (is rw)

31 Use case Frontend controller

This use case provides knowledge of Which data is required in order to display a category with products How is this data brought into Demandware How is this data extracted back out of Demandware How is this data displayed

40

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 41: gug-doc

Motivation context problem scenario

A specific type of frontend functionality is to be made available for all pages of a specific controller Here access to widgets and inits is particularly important as is the global gc object and splitting into sub-methods

Preconditions prior knowledge

Prior knowledge of Joose is necessary Furthermore this topic also goes hand-in-hand with frontend_widgets and frontend_inits since access to these widgets is possible from frontend controllers

When you wish to execute JavaScript functionality on HTML elements these elements receive a js_ class (eg class=js_controller or class=js_zoom) JavaScript functionality is never executed on classes that are reserved only for CSS (eg class=zoom) This standard must be observed

The following prerequisites must also be acknowledged

1 In cartridgestaticdefaultextensionsjsyslbocontroller a file must be created that matches the name of the backend controller eg ProductControllerjs

2 Loading of the file takes place in staticdefaultextensionsjsbasicjs via an entry with extensionsjsyslclcontrollerProductControllerjs The file is included with every request but is applied only in cases where we have ProductController active in the backend (see controllerProductds)

Implementation

Once the preconditions have been satisfied then a frontend controller for inserting frontend functionality can be implemented for a complete backend controller The following sections list the steps necessary to do so

Creating the basic frameworkgcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function ()

nodeReady function (node)

41

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 42: gug-doc

))

The controller must inherit from ApplicationController or from another controller that inherits from ApplicationController

The rootNode property

The rootNode property is the DOM element with the js_controller class It is the root element for all DOM elements for this controller and should also be utilized as such

Examplegcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController methods ready function () var self = this var $looks = thisrootNodefind(pddetails looks li) $lookseach(function() selfinitColorAndSizeSelector($(this)) ) ))

ready() and nodeReady()

The ready function is executed once all DOM elements have been loaded and can thus be used for the initialization of the controller ndash so as to access sub-methods for example and thus bind functionality to DOM elements It is executed exactly once

A nodeReady method also exists which can be created in the controller This is executed both on loading the controller and also after each AJAX request It contains a parameter that corresponds to the thisrootNode element on the initial loading of the controller and which corresponds to the AJAX response after being called by an AJAX request (eg to the elements loaded by AJAX)

Accessing return values from the backend controller

Sub-methods

It is generally a very good idea to split up controller functionality into a set of sub-methods instead of writing all of the functionality into the ready() method

Example

42

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 43: gug-doc

gcnamespace(yslclcontroller function() Class(yslclcontrollerProductController isa yslclcontrollerApplicationController has products is rw init function() return methods ready function ()

var self = this thisrootNodefind(pddetails looks li)each(function() selfinitColorAndSizeSelector($(this)) )

selfinitChartSwitching() selfinitCartAddCountryWarning()

initColorAndSizeSelector function($node)

initChartSwitching function()

initCartAddCountryWarning function()

has properties

Access to Weet URLs

The Weet object is global and therefore also available in controllersinitColorAndSizeSelector function($node) variant = selfproducts[id] = selectorstart(Weetget(products + id))

Access to widgets and inits

The main difference between widgets and inits is that widgets are initialized automatically when the page is accessed They function a little like controllers except that they are initialized for each request ndash and not just for pages that match the corresponding backend controller

43

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 44: gug-doc

Inits on the other hand must be instantiated directly from the controller However this functions as usual with the new parameter and the specification of the Joose namespace

images = new yslclinitproductImagesProductImages(parameter1 parameter2 )

32 Use case Sharable widget

This use case provides knowledge of

bull Embedding Twitter Facebook share linksbull Widget construction using the Sharable widget (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the widget concept (see recipe)

Embedding the Sharable widget

The Sharable widget is embedded by adding the js_sharelink class for any link as desired eglta $ doNothingHref() class=js_sharelink data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Faceookltagt

Here the parameters are passed via data- attributes these function as follows

data-sharingurl The url to share If no url is provided locationhref is used

data-sharingtext The text to share Can contain a placeholder 1 for the url

data-sharingwhere The plattform to share this link on Supported are twitter and facebook

Creating the basic framework

The initialization of the widget takes place using the nodeReady methodvar namespace = yslclwidgetssharablegcwidget(namespace function() var widget = this

widgetnodeReady = function($node) $nodedelegate(js_sharelink click function(e)

44

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 45: gug-doc

widgetSharableshareLinkClick($(this)) ) )

This delegates all clicks to the instances of js_sharelink found in the $node to a Joose class named Sharable This then contains the actual implementation of the desired functionality

33 Recipe Sharing a product page

This recipe provides knowledge of

Motivation context problem scenario

Various solutions

Contents

a) Facebook Like buttonb) FacebookTwitter share linkc) Others

a) Facebook Like button

To integrate the Facebook Like button the plug-in from Facebook is utilized A detailed set of plug-in documentation is available at developersfacebookcomdocsreferencepluginslike The iFrame version of the plug-in is deployed

The following steps must be carried out

bull Generate a script tag on the above-mentioned Facebook pagebull Embed the generated script tag in the ISML templatebull Embed og tags in the page header

Additional embedding of scripts is not required

Note

If a user clicks the Facebook Like button it is always the URL set in the og tag in the page header that is sent to Facebook ndash not the URL entered on the button itself If the URL or Weet hash is changed by JavaScript following the loading of the page this does not change the URL passed to Facebook

A practical example of this is the product page A single product page is used to present a number of product variants For the different product variants only the Weet hash is changed by JavaScript Accordingly this enables a page to be accessed directly However the Facebook Like button always sends the default URL of the product

45

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 46: gug-doc

List of og tags usedltmeta property=ogtitle content=value for page title gtltmeta property=ogtype content=product gtltmeta property=ogimage content=value for image url gtltmeta property=ogurl content=value for canonical permanent URL of the page gtltmeta property=ogdescription content=value for description of page content gtltmeta property=ogsite_name content=value for site name eg YSL gt

b) FacebookTwitter share link

To embed a FacebookTwitter share link the corresponding link must contain the following attributes or CSS classes CSS class js_sharelink data-sharingurl MY_PAGE_URL (URL of the page) data-sharetext MY_SHARETEXT (text to display on FacebookTwitter) data-sharewhere MY_SHARETARGET (target FacebookTwitter)

Examplelta href=javascript class=js_sharelink facebook data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=facebookgtShare on Facebookltagtlta href=javascript class=js_sharelink twitter data-sharingurl=$ shareUrl data-sharetext=$ shareText data-sharewhere=twittergtShare on Twitterltagt

To generate the URL accessed for FacebookTwitter the Sharable widget is utilized (widgetssharablejs) For nodeReady this widget binds a click handler to all links with the js_sharelink CSS class When the link is clicked the shareLinkClick method of the Sharable class is called The values of the data- attributes named above are extracted and a URL is generated

The URL is generated according to the following pattern httpwwwfacebookcomsharerphpu=MY_PAGE_URLampt=MY_PAGE_TITLE httptwittercomhomestatus=SHARETEXT

Note

The maximum length of a Twitter post (tweet) is 140 characters Here passing a Weed hash and thus the direct linking to a product variant ndash as with the Facebook Like button ndash is not possible The Facebook share link on the other hand supports URLs inclusive of the Weed hash

c) Others

In addition to the above-mentioned sharing systems for Facebook and Twitter the user is offered the following options for sharing pages within the Gucci projects

bull Share Blogparts Code block with linked image for embedding on other pages

46

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 47: gug-doc

bull Email to Friend Used to send an email with a personal message and URL of the page to be shared

bull Click to Copy Input field with the URL of the page to be shared for simple copying

Outlook

With all three variants it is possible to pass the complete URL including the Weed hash

34 Use Case Frontend JavaScript inits

Inits serve to permit the re-use of JavaScript that as a rule is activated only if explicitly initialized by a controller

Unlike widgets inits do not register a nodeReady function

Motivation context problem scenario

Conventions

Inits that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclinit folder eg

cartridgestaticdefaultextensionsjsgcclinitlightbox_managerjs

Project-specific inits on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclinit eg

cartridgestaticdefaultextensionsjssmcclinitzoomablejs

Solution model 1 Simple init (without Joose class)

In the simplest case an init can simply make one or more methods available within its namespace eg

gcinit(smcclinitlog function() thisdebug = function(str) consolelog(str) )

This function can now be used anywheresmcclinitlogdebug(Hello World)

Solution model 2 Complex init (with Joose class)

For more complex inits we recommend the provisioning of one or more Joose classes which are then initialized in one of the controllers eg

gcinit(smcclinitvideoPlayer function() Class(smcclwidgetsvideoPlayerPlayer

47

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 48: gug-doc

has options null player null methods initialize function(options) thisoptions = options

thisplayer = jwplayer(optionsid) if (optionsautoPlay) thisplay() play function() thisplayerplay() ))

This init class can now be used anywherevar player = new smcclinitvideoPlayerPayer( id my-element autoPlay true)

Implementation

All inits are defined using the gcinit(namespace fn) method In the process the fn closure passed is called once and grants the init its definition in an isolated namespace

Advantages

bull Generally inits and widgets have similar advantagesbull Unlike widgets initialization is on a demand-only basis ndash this may offer better

performancebull During initialization it is easy to pass additional parameters which may also be entirely

independent from the underlying DOM structure

Disadvantages

bull Since inits are initialized explicitly this logic must be re-initialized in every controller that utilizes the init

Outlook

The systematic implementation of the inits described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

48

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 49: gug-doc

35 Use Case Frontend JavaScript widgets

Widgets serve to organize the kinds of JavaScript functionality that are activated automatically as soon as a suitable DOM structure is available This is achieved by the widget defining a nodeReady function and inspecting the element thereby passed for suitable js_ classes

Unlike inits widgets are as a rule activated automatically and are not regulated by a controller

Motivation context problem scenario

Conventions

Widgets that should be available in all pages are stored in the global project in the cartridgestaticdefaultextensionsjsgcclwidgets folder eg

cartridgestaticdefaultextensionsjsgcclwidgetslightbox_managerjs

Project-specific widgets on the other hand are stored directly in the project repository cartridgestaticdefaultextensionsjssmcclwidgets eg

cartridgestaticdefaultextensionsjssmcclwidgetszoomablejs

Solution model 1 Simple widgets (without Joose class)

For simple widgets that do not contain any complex workflows or states we recommend the exclusive use of jQuery without Joose classes eg

gcwidget(smcclwidgetszoomable function () thisnodeReady = function($node) $node find(js_zoomable) click(function() Dieser code wird fuumlr jeden click auf ein js_zoomable event abgefangen ) )

Here the nodeReady method is always called when new elements are loaded into the document and also on the initial page load Here the $node parameter always references the jQuery parent element subsequently loaded

Solution model 2 Complex widgets (with Joose class)

For more complex widgets however we recommend working with Joose classes This may then look as follows

gcwidget(smcclwidgetszoomable function () var widget = this

thisnodeReady = function($node)

49

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 50: gug-doc

new widgetZoomable($node) )

Class(smcclwidgetszoomableZoomable has $node null methods initialize function($node) this$node = $node

var self = this this$nodeclick(function() selfzoom() ) zoom function() this $node find(js_zoomimage) show() )

The advantage here consists of the less cluttered structuring of individual behavioral elements In addition Joose classes also enable the user-friendly administration of additional variables and states that are not represented in the DOM

Implementation

All widgets are defined using the gcwidget(namespace fn) method In the process the fn closure passed is called once and grants the widget its definition in a namespace isolated from other widgets

Advantages

bull Widgets permit the re-use of interactive JavaScriptbull Joose classes enable clean structuring for the individual parts of the codebull The nodeReady method means widgets also function in elements subsequently loaded

by AJAXbull The use of js_classes as selectors ensures a distinction is made between CSS classes

used for style purposes and classes that influence page behaviorbull Via the targeted selecting of elements in the $node element it is not necessary to search

through the entire DOM each time

50

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 51: gug-doc

Disadvantages

bull Although the use of js_ classes ensures a certain decoupling of behavior from style re-use can nonetheless lead to problems that are specific to DOM or the layout

bull On the initial page load a large number of selectors can be involved which may well impact the performance of the loading process

Outlook

The systematic implementation of the widgets described above is handled with varying degrees of success in individual cases In the future more attention should be paid to the systematic utilization of the techniques described

36 Use case Video player init

This use case provides knowledge of

bull Embedding the video player initbull Init construction using the Video Player init (YSL project) as an example

Motivation context problem scenario

Preconditions prior knowledge

bull Basic knowledge of Joosebull Basic knowledge of the init concept (see recipe)

Embedding the video player init

The embedding of the Video Player init is achieved by explicit initialization in one of the controllers eg

gcnamespace(yslclcontroller function()

Class(yslclcontrollerVideoFragmentController isa yslclcontrollerFragmentController

methods ready function () var node = thisrootNode new yslclinitvideoPlayerVideoPlayer(nodefind(video)) ))

In the process the constructor of the VideoPlayer class expects a jQuery object that contains the desired video element Here the corresponding markup must be similar or identical to the following template

51

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 52: gug-doc

cartridgetemplatesdefaultgridfragment_videoisml

In particular the jQuery element is expected to have a data-params attribute containing the following JSON

staticBaseUrl $staticlink() h264Src $contentvideo webmSrc oggSrc

Furthermore the init also expects the jQuery node passed to contain a video element egltvideo id=jwplayer width=972 height=469 controlsgt ltsource src=$contentvideo type=videomp4gtltvideogt

The id=jwplayer that can be seen here is also mandatory

Creating the basic framework

Since the video player entity is an init the only task to complete now is to define a Joose class in its own namespace

gcinit(yslclinitvideoPlayer function(m) Class(yslclinitvideoPlayerVideoPlayer has node is rw

methods initialize function(node) thisnode = node

Code um den player zu initialiseren ))

Unlike widgets no automated initialization occurs as a result of the nodeReady event

4 Recipe CSS

This section provides knowledge of - The use of LESS-CSS - Splitting of CSS files - CSS structure - Conversion for use in a live context

52

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 53: gug-doc

Motivation context problem scenario

The use of LESS-CSS

To create the stylesheet we use the library LESS-CSS One reason why we use LESS-CSS in the first place is the option it offers for splitting the content of the stylesheet into individual files which can then be combined back into a single() document later on This reduces the likelihood of conflicts when working in a team

In addition one can also author CSS more quickly since LESS-CSS will write out in full selectors specified with indented CSS formatting This does create the danger that one unintentionally creates excessively long selectors Authors need to be aware of this

Further we also use the following LESS-CSS options

bull Namespaces and mixins (mostly for CSS3 rules)bull var (for an overview of colors used among other things)bull Operations (eg to calculate box sizes)bull Color functions (to create uniform highlight colors)bull One-line comments

Client-side usage

In the HTML page the LESS-CSS JavaScript and the global LESS file is included in the HEAD area

ltlink rel=stylesheetless type=textcss href=PROJEKTNAMElessgtltscript src=lessjs type=textjavascriptgtltscriptgt

LESS-CSS caches the generated styles in the browser To ensure proper emptying of the cache during development a tried-and-tested approach is to call a refresh before the closing body tag

ltscript type=textjavascriptgt lessrefresh(true)ltscriptgt

A blank page may be shown in IE7 in certain cases If this happens comment out the refresh instruction

Splitting of CSS files

As already mentioned the main reason for splitting up the CSS files is to avoid conflicts arising from simultaneous editing by multiple developers However it does not make sense to split the file into too many parts This ends up being more confusing less helpful and also involves more time when loading on development machines If conflicts frequently occur for one particular file then this file can still be partitioned later on

We recommend the following split strategy

bull basic (Styles that are utilized on all pages global layout header sidebar footer )

53

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 54: gug-doc

bull home (Styles for the home page)bull forms (Styles for the forms)bull account (Styles for the account area)bull checkout (Styles for the checkout process)bull catalog (Styles for the shop area)bull lightbox (Styles for the lightboxes)bull 1024 (Styles for the iPad1024x layout)bull print (Specialized adjustments to the style for print preview based on the screen design)bull fonts (Custom font definitions)bull vars (LESS-CSS variables and mixin definition for CSS3 rules)

In addition there is a LESS file with the same name as the project this loads all other LESS files using an import instruction

Depending on the project there may be more or fewer LESS files ndash whatever makes sense to facilitate day-to-day work

CSS structure

The CSS structure is oriented on the HTML structure This is based on the SMaX grid

Accordingly the modules are grouped into the areas header sidebar main extra and footer

54

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 55: gug-doc

Conventions

Generally there is no right or wrong when it comes to the syntax of CSS rules We have developed the following conventions from best practice

bull Stylesheet valid to W3C CSS3 specbull Full utilization of the entire CSS21 standard (if no support for IE6)bull Use of CSS3 for optimized presentation on new browsersbull Short selectors but long enough so as to enable the use of generic classes (next prev left

button)bull Class names contain no() visual characteristics (blueBorderTop)bull No utilization of the ClearFix classbull Properties in the order of their influence on website appearance (eg float up front

color at the back)bull Definition of the main grid in pixels further subdivisions in percentbull Package decor images into spritesbull Always present fixes for IE7 and IE8 separately so that later one can find and remove

them easily when support for the corresponding browser is withdrawn

Conversion for use in a live context

The conversion of LESS files into CSS via lessjs is slightly slower than pure CSS but does not present problems in development mode However this would be too slow on the live server Accordingly the post-process script contains a step that generates the CSS files

1 Convert the LESS files with less and node into a stylesheet file2 Embed all images into the CSS using Base64MHTML3 CSS minification using YUI Compressor

As a result the following files are generated

bull PROJECTNAME-mincss (minified CSS file for IE7 over HTTPS)bull PROJECTNAME-min-mhtmlcss (minified CSS file with embedded images for IE8

(HTTPSHTTP) and IE7 (HTTP))bull PROJECTNAME-min-bas64css (minified CSS file with embedded images for all other

browsers over HTTP and HTTPS)

Embedding in HTML with the help of conditional commentslt--[if lt IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-mincss media=screenprojectionprint gtlt[endif]--gtlt--[if gte IE 8]gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt[endif]--gtlt--[if IE]gt--gt ltlink rel=stylesheet type=textcss href=PROJEKTNAME-min-base64css media=screenprojectionprint gtlt--lt[endif]--gt

55

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 56: gug-doc

5 Use case Make AMS content maintainable

This use case provides knowledge of

bull Creation of a template in AMSbull Creation of a model for storing the databull Exporting the assetmodel to Demandware

Motivation context problem scenario

Creating a page in AMS

The entire AMS is written in JavaScript and uses the Qooxdoo Framework for presentation An introduction to the framework can be found at getting started and an overview of the available elements is accessible from Widgets

Each Demandware page type in AMS consists of three parts

bull Qooxdoo windowbull Qooxdoo modelbull Node Exporter to Demandware

Qooxdoo window

The widget describes the user interface for editing a Demandware page type Each window must inherit from the qxuiwindowWindow class and contain the model property As an example a simple window is generated with simple text entry and localized text entry The two input boxes are labeled with the labels ( labelText labelLocalesText ) and linked to the properties of the model ( docField docLocaleField )

TemplateadminsourceclassamsbawidgetsTestPagejs qxClassdefine(amsbawidgetsTestPage extend qxuiwindowWindow construct function(brand) thisbase(arguments title for Window) this__createLayout() this__setupBinding()

properties model init null event changeModel apply __applyModel

56

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 57: gug-doc

members __form null __formCtrl null

__createLayout function() layoutmanager for the page var layout = new qxuilayoutHBox(5) thissetLayout(layout) this__form = new qxuiformForm() formaddGroupHeader(just a headline row 0 column 0 ) formadd(new qxuiformTextField() labelText null docField null) formadd(new amswidgetsLocalesText(localestext) labelLocalesText null docLocaleField null)

var saveBtn = new qxuiformButton(text for save button) saveBtnaddListener(execute this__saveBtnHandler this)

var closeBtn = new qxuiformButton(text for close button) closeBtnaddListener(execute this__closeBtnHandler this)

add buttons to form formaddButton(saveBtn) formaddButton(closeBtn)

this__form = form var renderer = new amswidgetsBlockRenderer(form) thisadd(renderer flex 1 )

__setupBinding function() this__formCtrl = new qxdatacontrollerForm(null this__form true) thisbind(model this__formCtrl model)

EVENT HANDLER __saveBtnHandler function() qxcoreInitgetApplication()block() this__formctrlupdateModel() thisgetModel()save( qxlangFunctionbind(function(data) thisclose() qxcoreInitgetApplication()unblock() this) [])

__closeBtnHandler function() close window thisclose()

57

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 58: gug-doc

__applyModel function(model) )

Qooxdoo model

The model describes the storage of data in the database and links the data to the elements on the user interface Accordingly the values are transferred from the database to the elements and on saving the window the data items ndash where changed ndash are updated from the elements to the model The fields _id _rev _attachments and couchrestType are internal database fields and must be available on each model All other required fields must be defined in the model and can then be linked in the window with the user interface element

DocumentadminsourceclassamsbamodelsTestDocumentjs qxClassdefine(amsbamodelsTestDocument extend amsmodelsAMSDocument

properties _id init null _rev init null _attachments init null couchrestType init null

docField init null event changeDocField docLocaleField init null event changeDocLocaleField check amsmodelsLocaleText )

Node Exporter

The Node Exporter has the task of transforming the database model into Demandware-compliant XML An XML schema is not known and the structure of the XML is based on Demandware exports

ExportnodeviewsbaamsbamodelsTestDocumentjs exportsmerge = function(doc config request cb) var helper = require(helper)init(request) helperinitLanguages(config)

58

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export
Page 59: gug-doc

var res = [] var options = attr jsonContent type test fields [docLocaleField] subtype subFields [] respush(ltxml version=10 encoding=UTF-8gt) respush(helpercontentTag(library xmlns httpwwwdemandwarecomxmlimpexlibrary2006-10-31 helpercontentTag(content content-id doccontentid helpercontentTag(online-flag true) + n + helpercontentTag(searchable-flag false) + n + helpercontentTag(page-attributes ) + n + helpercontentTag(custom-attributes n + helperlocalizeBody(custom-attribute doc options) ) + n ) + n )) cb(null images helpergetImages() data resjoin(n) + n )

exportsdelete = function(doc config request cb) thismerge(doc config request cb)

59

  • 11 Hello World - How do I create a new page
    • Motivation context problem scenario
    • Defining the URLs routes
      • Routes routing
        • Backend controller
        • Templating
        • Helper classes
        • i18n internationalization
        • Folder structure
          • 12 Use case Product detail page
            • Motivation context problem scenario
            • Preconditions prior knowledge
              • Demandware products
              • Import
              • GlobalData
                • Implementation
                  • Backend
                  • Frontend
                      • 13 Use case Category page
                        • Motivation context problem scenario
                        • Preconditions prior knowledge
                        • Implementation
                          • Server-side implementation
                          • Client-side implementation
                              • 14 Use case Checkout
                                • Motivation context problem scenario
                                • Preconditions prior knowledge
                                  • Functional requirements
                                  • Demandware settings
                                    • Implementation
                                      • Gift option
                                      • Coupon codes
                                      • Personal customer data (may need registration login)
                                      • Address details (shipment billing address)
                                      • Shipping types
                                      • Payment types
                                      • Order completion
                                          • 21 Reference for CurrentMasterProduct and CurrentVariantProduct
                                            • Structure and properties
                                            • Creating objects for products
                                              • Example 1 Creating a product with a master ID
                                              • Example 2 Creating a product with a variant ID
                                                  • 22 Recipe Content asset with jsonContent
                                                    • Motivation context problem scenario
                                                    • Solution model
                                                    • Implementation
                                                    • Advantages
                                                    • Disadvantages
                                                    • Outlook
                                                      • 23 Recipe Product detail page with globalData
                                                        • Motivation context problem scenario
                                                        • Solution model
                                                        • Implementation
                                                          • 24 Use case Send email
                                                            • Motivation context problem scenario
                                                            • Preconditions prior knowledge
                                                            • Overview of steps to be completed
                                                              • a) Configuration of MVCPipes
                                                              • b) Creation of a sendMailTo() helper method
                                                              • c) Implementation of the SendEmail helper in the controller of the relevant page
                                                              • d) Creation of an asset in Demandware Business Manager
                                                                • email_tell_a_friend asset
                                                                • Integration of asset within template
                                                                  • e) Creation of a business object in order to be able to validate and subsequently access data from the form
                                                                      • 31 Use case Frontend controller
                                                                        • Motivation context problem scenario
                                                                        • Preconditions prior knowledge
                                                                        • Implementation
                                                                          • Creating the basic framework
                                                                          • The rootNode property
                                                                          • ready() and nodeReady()
                                                                          • Accessing return values from the backend controller
                                                                          • Sub-methods
                                                                          • has properties
                                                                          • Access to Weet URLs
                                                                          • Access to widgets and inits
                                                                              • 32 Use case Sharable widget
                                                                                • Motivation context problem scenario
                                                                                • Preconditions prior knowledge
                                                                                • Embedding the Sharable widget
                                                                                  • Creating the basic framework
                                                                                      • 33 Recipe Sharing a product page
                                                                                        • Motivation context problem scenario
                                                                                        • Various solutions
                                                                                          • a) Facebook Like button
                                                                                          • b) FacebookTwitter share link
                                                                                          • c) Others
                                                                                            • Outlook
                                                                                              • 34 Use Case Frontend JavaScript inits
                                                                                                • Motivation context problem scenario
                                                                                                • Conventions
                                                                                                • Solution model 1 Simple init (without Joose class)
                                                                                                • Solution model 2 Complex init (with Joose class)
                                                                                                • Implementation
                                                                                                • Advantages
                                                                                                • Disadvantages
                                                                                                • Outlook
                                                                                                  • 35 Use Case Frontend JavaScript widgets
                                                                                                    • Motivation context problem scenario
                                                                                                    • Conventions
                                                                                                    • Solution model 1 Simple widgets (without Joose class)
                                                                                                    • Solution model 2 Complex widgets (with Joose class)
                                                                                                    • Implementation
                                                                                                    • Advantages
                                                                                                    • Disadvantages
                                                                                                    • Outlook
                                                                                                      • 36 Use case Video player init
                                                                                                        • Motivation context problem scenario
                                                                                                        • Preconditions prior knowledge
                                                                                                        • Embedding the video player init
                                                                                                          • Creating the basic framework
                                                                                                              • 4 Recipe CSS
                                                                                                                • Motivation context problem scenario
                                                                                                                • The use of LESS-CSS
                                                                                                                  • Client-side usage
                                                                                                                    • Splitting of CSS files
                                                                                                                    • CSS structure
                                                                                                                      • Conventions
                                                                                                                        • Conversion for use in a live context
                                                                                                                          • 5 Use case Make AMS content maintainable
                                                                                                                            • Motivation context problem scenario
                                                                                                                            • Creating a page in AMS
                                                                                                                            • Qooxdoo window
                                                                                                                              • Template
                                                                                                                                • Qooxdoo model
                                                                                                                                  • Document
                                                                                                                                    • Node Exporter
                                                                                                                                      • Export