DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks
  • How To Integrate a Web Component Into a Mobile App While Preserving Native UX
  • Virtual Reality and Augmented Reality in the Browser
  • The Most Popular Angular UI Libraries To Try in 2021

Trending

  • Build an MCP Server Using Go to Connect AI Agents With Databases
  • Failure Handling Mechanisms in Microservices and Their Importance
  • Solid Testing Strategies for Salesforce Releases
  • Subtitles: The Good, the Bad, and the Resource-Heavy
  1. DZone
  2. Coding
  3. Languages
  4. Developing with HTML5, CoffeeScript and Twitter's Bootstrap

Developing with HTML5, CoffeeScript and Twitter's Bootstrap

By 
Matt Raible user avatar
Matt Raible
·
Oct. 21, 11 · Interview
Likes (1)
Comment
Save
Tweet
Share
17.2K Views

Join the DZone community and get the full member experience.

Join For Free
this article is the fourth in a series about my adventures developing a fitness tracking application with html5, play scala, coffeescript and jade. previous articles can be found at:

  1. integrating scalate and jade with play 1.2.3
  2. trying to make coffeescript work with scalate and play
  3. integrating html5 boilerplate with scalate and play

developing features
after getting my desired infrastructure setup, i started coding like a madman. the first feature i needed was a stopwatch to track the duration of a workout, so i started writing one with coffeescript. after spending 20 minutes playing with dates and settimeout, i searched and found a stopwatch jquery plug-in . i added this to my app, deployed it to heroku , brought up the app on my iphone 3g, clicked start and started riding my bike to work.

when i arrived, i unlocked my phone and discovered that the time had stopped. at first, i thought this was a major setback. my disappointed disappeared when i found a super neat javascript stopwatch and kåre byberg's version that worked just fine. this stopwatch used settimeout, so by keeping the start time, the app on the phone would catch up as soon as you unlocked it. i ported kåre's script to coffeescript and rejoiced in my working stopwatch.


# created by kåre byberg © 21.01.2005. please acknowledge if used 
# on other domains than http://www.timpelen.com.
# ported to coffeescript by matt raible. also added hours support.
flagclock = 0
flagstop = 0
stoptime = 0
refresh = null
clock = null

start = (button, display) ->
  clock = display
  startdate = new date()
  starttime = startdate.gettime()
  if flagclock == 0
    $(button).html("stop")
    flagclock = 1
    counter starttime, display
  else
    $(button).html("start")
    flagclock = 0
    flagstop = 1

counter = (starttime) ->
  currenttime = new date()
  timediff = currenttime.gettime() - starttime
  timediff = timediff + stoptime  if flagstop == 1
  if flagclock == 1
    $(clock).val formattime timediff, ""
    callback = -> counter starttime
    refresh = settimeout callback, 10
  else
    window.cleartimeout refresh
    stoptime = timediff

formattime = (rawtime, roundtype) ->
  if roundtype == "round"
    ds = math.round(rawtime / 100) + ""
  else
    ds = math.floor(rawtime / 100) + ""
  sec = math.floor(rawtime / 1000)
  min = math.floor(rawtime / 60000)
  hour = math.floor(rawtime / 3600000)
  ds = ds.charat(ds.length - 1)
  start() if hour >= 24
  sec = sec - 60 * min + ""
  sec = prependzerocheck sec
  min = min - 60 * hour + ""
  min = prependzerocheck min
  hour = prependzerocheck hour
  hour + ":" + min + ":" + sec + "." + ds

prependzerocheck = (time) ->
  time = time + "" # convert from int to string
  unless time.charat(time.length - 2) == ""
    time = time.charat(time.length - 2) + time.charat(time.length - 1)
  else
    time = 0 + time.charat(time.length - 1)

reset = ->
  flagstop = 0
  stoptime = 0
  window.cleartimeout refresh
  if flagclock == 1
    resetdate = new date()
    resettime = resetdate.gettime()
    counter resettime
  else
    $(clock).val "00:00:00.0"

@stopwatch = {
  start: start
  reset: reset
}

the scalate/jade template to render this stopwatch looks as follows:


script(type="text/javascript" src={uri("/public/javascripts/stopwatch.coffee")})

#display
  input(id="clock" class="xlarge" type="text" value="00:00:00.0" readonly="readonly")
#controls
  button(id="start" type="button" class="btn primary") start
  button(id="reset" type="button" class="btn :disabled") reset

:plain
  <script type="text/coffeescript">
    $(document).ready ->
      $('#start').click ->
        stopwatch.start this, $('#clock')

      $('#reset').click ->
        stopwatch.reset()
  </script>

next, i wanted to create a map that would show your location. for this, i used merge design's html 5 geolocation demo as a guide. the html5 geo api is pretty simple, containing only three methods:

// gets the users current position
navigator.geolocation.getcurrentposition(successcallback,
                                         errorcallback,
                                         options);
// request repeated updates of position
watchid = navigator.geolocation.watchposition(successcallback, errorcallback);

// cancel the updates
navigator.geolocation.clearwatch(watchid);

after rewriting the geolocation example in coffeescript, i ended up with the following code in my map.coffee script. you'll notice it uses google maps javascript api to show an actual map with a marker.

# geolocation with html 5 and google maps api based on example from maxheapsize: 
# http://maxheapsize.com/2009/04/11/getting-the-browsers-geolocation-with-html-5/
# this script is by merge database and design, http://merged.ca/ -- if you use some, 
# all, or any of this code, please offer a return link.

map = null
mapcenter = null
geocoder = null
latlng = null
timeoutid = null

initialize = ->
  if modernizr.geolocation
    navigator.geolocation.getcurrentposition showmap

showmap = (position) ->
  latitude = position.coords.latitude
  longitude = position.coords.longitude
  mapoptions = {
    zoom: 15,
    maptypeid: google.maps.maptypeid.roadmap
  }
  map = new google.maps.map(document.getelementbyid("map"), mapoptions)
  latlng = new google.maps.latlng(latitude, longitude)
  map.setcenter(latlng)

  geocoder = new google.maps.geocoder()
  geocoder.geocode({'latlng': latlng}, addaddresstomap)

addaddresstomap = (results, status) ->
  if (status == google.maps.geocoderstatus.ok) 
    if (results[1]) 
      marker = new google.maps.marker({
          position: latlng,
          map: map
      })
      $('#location').html('your location: ' + results[0].formatted_address)
  else 
    alert "sorry, we were unable to geocode that address."

start = ->
  timeoutid = settimeout initialize, 500

reset = ->
  if (timeoutid)
    cleartimeout timeoutid

@map = {
  start: start
  reset: reset
}

the template to show the map is a mere 20 lines of jade:

script(type="text/javascript" src="http://www.google.com/jsapi")
script(type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false")

:css
  .demo-map {
    border: 1px solid silver;
    height: 200px;
    margin: 10px auto;
    width: 280px;
  }

#map(class="demo-map")

p(id="location")
  span(class="label success") new
  | fetching your location with html 5 geolocation...

script(type="text/javascript" src={uri("/public/javascripts/map.coffee")})
:javascript
    map.start();

the last two features i wanted were 1) distance traveled and 2) drawing the route taken on the map. for this i learned from a simple trip meter using the geolocation api . as i was beginning to port the js to coffeescript, i thought, "there's got to be a better way." i searched and found js2coffee to do most of the conversion for me. if you know javascript and you're learning coffeescript, this is an invaluable tool.

i tried out the trip meter that night evening on a bike ride and noticed it said i'd traveled 3 miles when i'd really gone 6. i quickly figured out it was only calculating start point to end point and not taking into account all the turns in between. to view what was happening, i integrated my odometer.coffee with my map using google maps polylines . upon finishing the integration, i discovered two things, 1) html5 geolocation was highly inaccurate and 2) geolocation doesn't run in the background .

i was able to solve the first problem by passing in {enablehighaccuracy: true} to navigator.geolocation.watchposition(). below are two screenshots showing before high accuracy and after. both screenshots are from the same two-block walk.

without {enablehighaccuracy: true} with {enablehighaccuracy: true}


the second issue is a slight show-stopper. phonegap might be able to solve the problem, but i'm currently using a workaround → turning off auto-lock and keeping safari in the foreground.

making it look good
after i got all my desired features developed, i moved onto making the app look good. i started by using sass for my css and installed play's sass module . i then switched to less when i discovered and added twitter's bootstrap to my project. at first i used play's less module (version 0.3), but ran into compilation issues . i then tried play's greenscript module , but gave up on it when i found it was incompatible with the coffeescript module . switching back to the less module and using the "0.3.compatibility" version solved all remaining issues.

you might remember that i integrated html5 boilerplate and wondering why i have both bootstrap and boilerplate in my project. at this point, i don't think boilerplate is needed, but i've kept it just in case it's doing something for html5 cross-browser compatibility. i've renamed its style.css to style.less and added the following so it has access to bootstrap's variables.

/* variables from bootstrap */
@import "libs/variables.less";

then i made my app look a lot better with layouts, stylish forms , a fixed topbar and alerts . for example, here's the coffeescript i wrote to display geolocation errors:

geolocationerror = (error) ->
  msg = 'unable to locate position. '
  switch error.code
    when error.timeout then msg += 'timeout.'
    when error.position_unavailable then msg += 'position unavailable.'
    when error.permission_denied then msg += 'please turn on location services.'
    when error.unknown_error then msg += error.code
  $('.alert-message').remove()
  alert = $('<div class="alert-message error fade in" data-alert="alert">')
  alert.html('<a class="close" href="#">×</a>' + msg);
  alert.insertbefore($('.span10'))

then i set about styling up the app so it looked good on a smartphone with css3 media queries . below is the less code i used to hide elements and squish the widths for smaller devices.

@media all and (max-device-width: 480px) {
  /* hide scrollbar on mobile */
  html { overflow-y:hidden }
  /* hide sidebar on mobile */
  .home .span4, .home .page-header, .topbar form {
    display: none
  }
  .home .container {
    width: 320px;
  } 
  .about {
    .container, .span10 {
      width: 280px;
    }
    .span10 {
      padding-top: 0px;
    }
  }

tools
in the process of developing a stopwatch, odometer, displaying routes and making everything look good, i used a number of tools. i started out primarily with textmate and its bundles for less , coffeescript and jade . when i started writing more scala, i installed the scala textmate bundle . when i needed some debugging, i switched to intellij and installed its scala plugin. coffeescript, less and haml plugins (for jade) were already installed by default. i also used james ward's setup play framework with scala in intellij .

issues
i think it's obvious that my biggest issue so far is the fact that a webapp can't multitask in the background like a native app can. beyond that, there's accuracy issues with html5's geolocation that i haven't seen in native apps.

i also ran into a caching issue when calling getcurrentposition(). it only worked the first time and i had to refresh my browser to get it to work again. strangely enough, this only happened on my desktop (in safari and firefox) and worked fine on my iphone. unfortunately, it looks like phonegap has issues similar to this.

my workaround for no webapp multitasking is turning off auto-lock and leaving the browser in the foreground while i exercise. the downside to this is it really drains the battery quickly (~ 3 hours). i constantly have to charge my phone if i'm testing it throughout the day. the testing is a real pain too. i have to deploy to heroku (which is easy enough), then go on a walk or bike ride. if something's broke, i have to return home, tweak some things, redeploy and go again. also, there's been a few times where safari crashes halfway through and i lose all the tracking data. this happens with native apps too, but seemingly not as often.

if you'd like to try the app on your mobile phone and see if you experience these issues, checkout play-more.com .

summary
going forward, there's still more html5 features i'd like to use. in particular, i'd like to play music while the fitness tracker is running. i'd love it if cloud music services (e.g. pandora or spotify) had an api i could use to play music in a webapp. soundcloud might be an option, but i've also thought of just uploading some mp3s and playing them with the <audio> tag.

i've really enjoyed developing with all these technologies and haven't experienced much frustration so far. the majority has come from integrating scalate into play, but i've resolved most problems. next, i'll talk about how i've improved play's scalate support and my experience working with anorm .


source: http://raibledesigns.com/rd/entry/developing_with_html5_coffeescript_and
Coffeescript HTML mobile app Bootstrap (front-end framework)

Opinions expressed by DZone contributors are their own.

Related

  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks
  • How To Integrate a Web Component Into a Mobile App While Preserving Native UX
  • Virtual Reality and Augmented Reality in the Browser
  • The Most Popular Angular UI Libraries To Try in 2021

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!