This is the additional part to the previous tutorial Create a self caching website ready for offline usage with HTML5 and jQuery . Our script is able to cache and restore markup, stylesheets and javascripts. Basically everything you need to make a kick-ass website. All of these assets are simple text and can be cached/restored as is . But how could we cache non-text based content, such as images, in HTML5’s localStorage ?

How does it basically work?

Images can be represented as Base64 encoded data URI scheme . This technique has been around for quite a while and is supported by all modern browsers.

  1. <img alt=”Image represented as data URI” src=”data:image/png;base64,…” />

To generate this data URI scheme we use another feature of HTML5, the Canvas element . To be more specific, we only use two functions: drawImage() to get the image onto the Canvas element, and toDataURL() to generate the Base64 encoded data URI.

Preload images when online

We need to make sure that every image we want to cache is fully loaded. In that case we create a dummy image object and apply the jQuery load() event.

  1. encodeImageBase64: (img) -> # use canvas to get a base64 encoded string of the image
  2. canvas =createElement(‘canvas’) # create a temporary canvas element
  3. width = img.width # set width and..
  4. canvas.height =height # ..height of the canvas to fit the complete image
  5. context =getContext(‘2d’) # get the context for the canvas element
  6. drawImage img, 0, 0 # draw the image into the context
  7. toDataURL ‘image/jpg’ # and return the base64 encoded data url of the complete canvas

Store the data URI scheme in localStorage

We already have a function to store data in the localStorage. Encode the image and store it.

  1. loadImageCallback: (imgEl) ->
  2. encoded = @encodeImageBase64(get(0)) # encode the image to a base64 data URI
  3. @loadAssetCallback imgEl.attr(‘src’), encoded # store encoded image in local storage

Restore images when offline

Restoring images from the localStorage cache is pretty simple. We replace the src attribute of the original image with the data URI scheme. That’s it!

  1. restoreImages: -> # restore all images from cache if possible
  2. self = @ # keep a reference to this
  3. images = $ ‘img’, @bodyEl # get all image elements, use

The complete script

  1. class SCOW
  2. constructor: ->
  3. @headEl = $ ‘head’ # snapshot of the head element
  4. @bodyEl = $ ‘body’ # snapshot of the body element
  5. @curFileName = @getFileName() # get the requested path
  6. @assets = @getStorage(‘assets’) # initialize assets index
  7. if @assets is null # if there is no assets index yet
  8. @assets = [‘js/jquery.js’, ‘js/scow.js’] # create it, these two assets are cached by appcache
  9. @setStorage ‘assets’, @assets # and store it
  10. addEventListener ‘updateready’, -> # if the manifest files are newly cached
  11. clear() # clear also local store
  12. ifonLine # check if there is a internet connection
  13. @cacheCurrentFile() # if so cache the current file
  14. else
  15. @restoreFromCache() # try to restore the requested file from cache
  16. ifhost.indexOf(‘localhost’) isnt 1 # check if we are in dev mode
  17. $(‘#new-cache’).show() # if so show the link to trigger a new cache via /new_cache
  18. @updateAssetsIndex() # output the current asset index
  19. getFileName: ->
  20. path = location.pathname.split(‘/’) # get current pathname and split it by /
  21. filename = path[length 1] # last part in array is filename
  22. iflength is 0 # check if the root path / is requested
  23. filename = ‘index.html’ # fallback to index.html
  24. filename # return filename
  25. getStorage: (name) -> # helper function to read/decode JSON from local storage
  26. item = localStorage.getItem(name) # try to read from local storage
  27. if item isnt null # item was found in storage
  28. item = JSON.parse(item) # json encoded object
  29. item # return the object or null if not found
  30. setStorage: (name, value) -> # helper function to write/encode JSON to local storage
  31. item = JSON.stringify(value) # create json string
  32. setItem name, item # write json string to local storage
  33. updateAssetsIndex: -> # output cached files in a list for the demo
  34. listEl = $ ‘#cached-files’ # we dont cache this list element globally because it could change in $body
  35. children().remove() # remove all previously added list items
  36. for asset in @assets # for every path in the assets index
  37. append “

as context images.each -> # process every image $(new Image()) # create a dummy image object .attr(‘src’, $(@).attr(‘src’)) # load from the same path as found in the image element .load -> # add a load event for the dummy image self.loadImageCallback $(@) # trigger the callback and pass the jquery object for the image cacheCurrentFile: -> # cache the requested .html file cssAssets = @getAssets(‘link[rel=”stylesheet”]’, ‘href’) # get array of stylesheets jsAssets = @getAssets(‘script’, ‘src’) # get array of javascripts cacheObj = # this will hold the cached page and all assets references bodyHtml : @bodyEl.html() # cache the content of the current file title : document.title # cache the title stylesheets: cssAssets # array with all stlesheets javascripts: jsAssets # array with all javascripts @loadAssetCallback(@curFileName, cacheObj) # manually invoke the callback and save the object @loadAssets cssAssets # begin to load all the css assets @loadAssets jsAssets # same with the javascripts @loadImages() # begin to load, encode and cache images restoreHeader: (paths, wrapper) -> # reassemble and include the cached files combined = ” # include all in one string for path in paths # go through all cached assets content = @getStorage(path) # try to get the content from local storage if content isnt null # check if the requested file is cached combined += content # add the cached content $(wrapper) # create a jquery object from the wrapper markup .text(combined) # set the content .appendTo @headEl # and append it to the head restoreImages: -> # restore all images from cache if possible self = @ #keep a reference to ‘this’ images = $ ‘img’, @bodyEl # get all image elements, use

Leave a Reply

Your email address will not be published. Required fields are marked *