Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

initial commit

  • Loading branch information...
commit b5af4875cd8af70841e83dabaafb18e7f0139a3f 0 parents
Rebecca Murphey authored
2  .gitignore
... ... @@ -0,0 +1,2 @@
  1 +www/js/dojo-release-1.6.0-src
  2 +dist
23 README.md
Source Rendered
... ... @@ -0,0 +1,23 @@
  1 +# Using the Dojo Toolkit for MVC JavaScript applications
  2 +
  3 +This is a repository based on the [Dojo
  4 +Boilerplate]https://github.com/rmurphey/dojo-boilerplate/) for demonstrating
  5 +simple MVC concepts using the [Dojo Toolkit](http://dojotoolkit.org).
  6 +
  7 +This repository is set up to work using a version of Dojo hosted on the Google
  8 +CDN. If you'd prefer to use a local version of Dojo -- or if you're interested
  9 +in trying out the build script at `util/build.sh` -- you'll need to run the
  10 +setup script at `util/setup.sh` to download the full Dojo SDK. You'll also need
  11 +to
  12 +
  13 +# Useful resources
  14 +
  15 +* [Dojo Reference Guide](http://dojotoolkit.org/reference-guide/)
  16 +* [Introduction to Custom Dojo
  17 + Widgets](http://www.enterprisedojo.com/2010/09/21/introduction-to-custom-dojo-widgets/)
  18 +
  19 +# License
  20 +
  21 +The Dojo Boilerplate is licensed under the [same
  22 +terms](http://bugs.dojotoolkit.org/browser/dojo/trunk/LICENSE) as the Dojo
  23 +Toolkit.
25 profiles/app.js
... ... @@ -0,0 +1,25 @@
  1 +dependencies = {
  2 + stripConsole : 'all',
  3 + action : 'clean,release',
  4 + optimize : 'shrinksafe',
  5 + releaseName : 'js',
  6 + localeList : 'en-us',
  7 +
  8 + layers: [
  9 + {
  10 + name: "../app/base.js",
  11 + resourceName : "app.base",
  12 + dependencies: [
  13 + "app.base"
  14 + ]
  15 + }
  16 + ],
  17 +
  18 + prefixes: [
  19 + [ "dijit", "../dijit" ],
  20 + [ "dojox", "../dojox" ],
  21 + [ "app", "../../app" ],
  22 + [ "dbp", "../../dbp" ]
  23 + ]
  24 +}
  25 +
43 util/build.sh
... ... @@ -0,0 +1,43 @@
  1 +#!/bin/bash
  2 +
  3 +set -e
  4 +
  5 +DOJOVERSION="1.6.0"
  6 +
  7 +THISDIR=$(cd $(dirname $0) && pwd)
  8 +SRCDIR="$THISDIR/../www"
  9 +UTILDIR="$SRCDIR/js/dojo-release-${DOJOVERSION}-src/util/buildscripts"
  10 +PROFILE="$THISDIR/../profiles/app.js"
  11 +CSSDIR="$SRCDIR/css"
  12 +DISTDIR="$THISDIR/../dist"
  13 +
  14 +if [ ! -d "$UTILDIR" ]; then
  15 + echo "Can't find Dojo build tools -- did you run ./util/setup.sh?"
  16 + exit 1
  17 +fi
  18 +
  19 +if [ ! -f "$PROFILE" ]; then
  20 + echo "Invalid input profile"
  21 + exit 1
  22 +fi
  23 +
  24 +echo "Using $PROFILE. CSS will be copied and JS will be built."
  25 +
  26 +# clean the old distribution files
  27 +rm -rf "$DISTDIR"
  28 +
  29 +# i know this sucks, but sane-er ways didn't seem to work ... :(
  30 +cd "$UTILDIR"
  31 +./build.sh profileFile=../../../../../profiles/app.js releaseDir=../../../../../dist/
  32 +cd "$THISDIR"
  33 +
  34 +# copy the css files
  35 +# todo: how to do this better?
  36 +cp -r "$CSSDIR" "$DISTDIR/css"
  37 +
  38 +# copy the index.html and make it production-friendly
  39 +cp "$SRCDIR/index.html" "$DISTDIR/index.html"
  40 +
  41 +
  42 +sed -i -e "s/var _dbpDev = true;//" "$DISTDIR/index.html"
  43 +sed -i -e "s/js\/dojo-release-1.6.0-src/dist/" "$DISTDIR/index.html"
30 util/setup.sh
... ... @@ -0,0 +1,30 @@
  1 +#!/bin/bash
  2 +
  3 +set -e
  4 +
  5 +VERSION="1.6.0"
  6 +
  7 +THISDIR=$(cd $(dirname $0) && pwd)
  8 +OUTDIR="$THISDIR/../www/js"
  9 +DOJODIR="dojo-release-${VERSION}-src"
  10 +OUTDIR=$(cd "$OUTDIR" &> /dev/null && pwd || echo "")
  11 +
  12 +if which wget >/dev/null; then
  13 + GET="wget --no-check-certificate -O -"
  14 +elif which curl >/dev/null; then
  15 + GET="curl -L --insecure -o -"
  16 +else
  17 + echo "No cURL, no wget, no downloads :("
  18 + exit 1
  19 +fi
  20 +
  21 +if [ "$OUTDIR" = "" ]; then
  22 + echo "Output directory not found"
  23 + exit 1
  24 +fi
  25 +
  26 +if [ ! -d "$OUTDIR/$DOJODIR" ]; then
  27 + echo "Fetching Dojo $VERSION"
  28 + $GET http://download.dojotoolkit.org/release-$VERSION/$DOJODIR.tar.gz | tar -C "$OUTDIR" -xzf -
  29 + echo "Dojo extracted to $OUTDIR/$DOJODIR"
  30 +fi
110 www/css/app.css
... ... @@ -0,0 +1,110 @@
  1 +body {
  2 + background-color:#222;
  3 + color:#f0f0f0
  4 +}
  5 +
  6 +#container {
  7 + width:970px;
  8 + font-family: Helvetica, Arial, sans-serif;
  9 + margin: 20px auto;
  10 + overflow:hidden;
  11 +}
  12 +
  13 +#people {
  14 + background-color:#ff6600;
  15 + -webkit-border-radius:10px;
  16 + -moz-border-radius:10px;
  17 + padding:15px;
  18 + margin:0 0 40px 0;
  19 + overflow:hidden;
  20 + font-weight:bold;
  21 +}
  22 +
  23 +#people li {
  24 + float:left;
  25 + margin:0 15px 0 0;
  26 + cursor: pointer;
  27 +}
  28 +
  29 +.person .info {
  30 + display: -webkit-box;
  31 + -webkit-box-orient: horizontal;
  32 +
  33 + display: -moz-box;
  34 + -moz-box-orient: horizontal;
  35 +
  36 + display: box;
  37 + box-orient: horizontal;
  38 +}
  39 +
  40 +ul {
  41 + margin: 0;
  42 + padding:0;
  43 +}
  44 +
  45 +ul li {
  46 + list-style:none;
  47 + margin:0 0 1.2em 0;
  48 +}
  49 +
  50 +p {
  51 + line-height: 1.2em;
  52 + margin:0 0 0.5em 0;
  53 +}
  54 +
  55 +.latest-tweet {
  56 + color:#000;
  57 + background-color: #f5c700;
  58 + -webkit-border-radius: 10px;
  59 + -moz-border-radius: 10px;
  60 + padding:15px;
  61 + margin:0 0 2em 0;
  62 +}
  63 +
  64 +.latest-tweet li {
  65 + margin:0;
  66 +}
  67 +
  68 +.latest-tweet p.tweet {
  69 + font-size: 150%;
  70 +}
  71 +
  72 +.latest-tweet p.date {
  73 + margin: 0;
  74 +}
  75 +
  76 +p.date {
  77 + font-size:80%;
  78 +}
  79 +
  80 +a {
  81 + color: #c12552;
  82 + text-decoration:none;
  83 +}
  84 +
  85 +a:hover {
  86 + text-decoration:underline;
  87 +}
  88 +
  89 +.twitter {
  90 + -webkit-box-flex: 2;
  91 + padding:0 50px 0 0;
  92 +}
  93 +
  94 +.weather {
  95 + -webkit-box-flex: 1;
  96 + -webkit-border-radius: 10px;
  97 + -moz-border-radius: 10px;
  98 + padding:15px;
  99 + background-color: #008885;
  100 +}
  101 +
  102 +h3 {
  103 + margin:0 0 0.5em 0;
  104 +}
  105 +
  106 +.loading {
  107 + background-image: url(../img/loading.gif);
  108 + background-position: center;
  109 + background-repeat: no-repeat;
  110 +}
33 www/data/people.json
... ... @@ -0,0 +1,33 @@
  1 +[
  2 + {
  3 + "id" : 1,
  4 + "name" : "Alex Sexton",
  5 + "twitter" : "SlexAxton",
  6 + "location" : "Austin, TX",
  7 + "img" : "img/alex.png"
  8 + },
  9 +
  10 + {
  11 + "id" : 2,
  12 + "name" : "Paul Irish",
  13 + "twitter" : "paul_irish",
  14 + "location" : "San Francisco, CA",
  15 + "img" : "img/paul.png"
  16 + },
  17 +
  18 + {
  19 + "id" : 3,
  20 + "name" : "Adam Sontag",
  21 + "twitter" : "ajpiano",
  22 + "location" : "New York, NY",
  23 + "img" : "img/adam.png"
  24 + },
  25 +
  26 + {
  27 + "id" : 4,
  28 + "name" : "Rebecca Murphey",
  29 + "twitter" : "rmurphey",
  30 + "location" : "Durham, NC",
  31 + "img" : "img/rebecca.png"
  32 + }
  33 +]
BIN  www/img/adam.png
BIN  www/img/alex.png
BIN  www/img/loading.gif
BIN  www/img/paul.png
BIN  www/img/rebecca.png
51 www/index.html
... ... @@ -0,0 +1,51 @@
  1 +<!doctype html>
  2 +<html>
  3 +<head>
  4 + <meta charset="utf-8">
  5 + <title></title>
  6 + <link rel="stylesheet" href="css/app.css">
  7 +</head>
  8 +<body>
  9 +
  10 + <div id="container">
  11 + <div id="people"></div>
  12 + <div id="detail"></div>
  13 + </div>
  14 +
  15 + <!--
  16 +
  17 + uncomment this block to use a local dojo.js; note that you must
  18 + run the setup script at util/setup.sh in order for this to work.
  19 + note also that you'll need to remove the script tags that are currently
  20 + being used
  21 +
  22 + <script>
  23 + var _dbpDev = true;
  24 + djConfig = _dbpDev ? {
  25 + modulePaths : {
  26 + app : "../../app"
  27 + }
  28 + } : {};
  29 + </script>
  30 + <script src="js/dojo-release-1.6.0-src/dojo/dojo.js"></script>
  31 +
  32 + -->
  33 +
  34 + <script>
  35 + var _dbpDev = true;
  36 + djConfig = _dbpDev ? {
  37 + baseUrl : './',
  38 + modulePaths : {
  39 + app : "js/app",
  40 + dbp : "js/dbp"
  41 + }
  42 + } : {};
  43 + </script>
  44 + <script src="https://ajax.googleapis.com/ajax/libs/dojo/1.6.0/dojo/dojo.xd.js"></script>
  45 + <script>
  46 + dojo.ready(function() {
  47 + dojo.require("app.base");
  48 + });
  49 + </script>
  50 +</body>
  51 +</html>
91 www/js/app/base.js
... ... @@ -0,0 +1,91 @@
  1 +dojo.provide('app.base');
  2 +/**
  3 + * This file is your application's base JavaScript file;
  4 + * it is loaded into the page by the dojo.require() call in
  5 + * index.html. You can write code in this file, use it to
  6 + * express dependencies on other files, or both. Generally,
  7 + * this file should be used only for bootstrapping code;
  8 + * actual functionality should be placed in other files inside
  9 + * the www/js/app directory.
  10 + */
  11 +
  12 +/**
  13 + * You can specify dependencies on other files by adding
  14 + * dojo.require() statements for them:
  15 + *
  16 + * dojo.require('dijit.Dialog');
  17 + *
  18 + * This works for your application's files, too:
  19 + *
  20 + * dojo.require('app.Foo');
  21 + *
  22 + * The above would look for a file located at
  23 + * www/js/app/Foo.js; however, it's important to note
  24 + * that this only works because we've specified a modulePath for
  25 + * the 'app' namespace in index.html. If we do not specify a
  26 + * modulePath for a namespace, dojo.require will assume that the
  27 + * namespace corresponds to a directory that is a sibling of
  28 + * the directory that contains dojo.js. The modulePath setting
  29 + * in index.html overrides that default, providing a location
  30 + * for the namespace relative to the location of dojo.js.
  31 + *
  32 + * Note also that any files you include via dojo.require()
  33 + * MUST include a call to dojo.provide at the beginning;
  34 + * the dojo.provide() function should be passed a string
  35 + * that specifies how you expect the module to be referred
  36 + * to in dojo.require() calls:
  37 + *
  38 + * dojo.provide('app.Foo');
  39 + *
  40 + * Finally, note that you do not need to express all of your
  41 + * application's dependencies in this one file; individual files
  42 + * can express their own dependencies as well.
  43 + */
  44 +dojo.require('app.views.Person');
  45 +dojo.require('app.views.People');
  46 +dojo.require('app.models.People');
  47 +
  48 +/**
  49 + * Any functionality that depends on the DOM being available
  50 + * should be passed inside a function to dojo.ready. If you're
  51 + * making a single-page app, this is your application controller.
  52 + */
  53 +dojo.ready(function() {
  54 + var peopleData = app.models.People;
  55 +
  56 + // load the initial data for the page
  57 + dojo.when(peopleData.load(), function() {
  58 +
  59 + var people = peopleData.getPeople(),
  60 + peopleWidget = new app.views.People({ people : people }, 'people'),
  61 + personWidget,
  62 + person;
  63 +
  64 + dojo.connect(peopleWidget, 'onSelect', function(personId) {
  65 +
  66 + // destroy the old person widget if there is one
  67 + if (personWidget) { personWidget.destroy(); }
  68 +
  69 + // get an instance of the Person model for the requested person
  70 + person = peopleData.getPerson(personId);
  71 +
  72 + // set up the person widget, passing in the person model
  73 + personWidget = new app.views.Person({
  74 + person : person
  75 + }).placeAt('detail');
  76 +
  77 + // ask the model for the person's tweets, and pass them
  78 + // to the widget once we have them
  79 + person.getTweets().then(function(tweets) {
  80 + personWidget.set('tweets', tweets);
  81 + });
  82 +
  83 + // ask the model for the person's weather, and pass it
  84 + // to the widget once we have it
  85 + person.getWeather().then(function(weather) {
  86 + personWidget.set('weatherData', weather);
  87 + });
  88 +
  89 + });
  90 + });
  91 +});
34 www/js/app/models/People.js
... ... @@ -0,0 +1,34 @@
  1 +dojo.provide('app.models.People');
  2 +
  3 +dojo.require('dojo.store.Memory');
  4 +dojo.require('app.models.Person');
  5 +
  6 +(function() {
  7 +
  8 +var store;
  9 +
  10 +app.models.People = {
  11 + load : function() {
  12 + if (store) { return store.data; }
  13 +
  14 + return dojo.xhrGet({
  15 + url : 'data/people.json',
  16 + handleAs : 'json',
  17 + load : function(data) {
  18 + store = new dojo.store.Memory({ data : data });
  19 + }
  20 + });
  21 + },
  22 +
  23 + getPerson : function(id) {
  24 + return new app.models.Person(store.get(id));
  25 + },
  26 +
  27 + getPeople : function() {
  28 + return dojo.map(store.data, function(p) {
  29 + return new app.models.Person(p);
  30 + });
  31 + }
  32 +};
  33 +
  34 +}());
22 www/js/app/models/Person.js
... ... @@ -0,0 +1,22 @@
  1 +dojo.provide('app.models.Person');
  2 +
  3 +dojo.require('app.services.Twitter');
  4 +dojo.require('app.services.YQL');
  5 +
  6 +(function() {
  7 +
  8 +dojo.declare('app.models.Person', [], {
  9 + constructor : function(data) {
  10 + this.data = data;
  11 + },
  12 +
  13 + getTweets : function() {
  14 + return app.services.Twitter.tweets(this.data.twitter);
  15 + },
  16 +
  17 + getWeather : function() {
  18 + return app.services.YQL.weather(this.data.location);
  19 + }
  20 +});
  21 +
  22 +}());
33 www/js/app/services/Twitter.js
... ... @@ -0,0 +1,33 @@
  1 +dojo.provide('app.services.Twitter');
  2 +
  3 +dojo.require('dojo.io.script');
  4 +dojo.require('dojo.string');
  5 +
  6 +app.services.Twitter = {
  7 + tweets : function(username) {
  8 + console.log('username is', username);
  9 + var url = 'http://twitter.com/status/user_timeline/' + username + '.json',
  10 + dfd = new dojo.Deferred();
  11 +
  12 + dojo.io.script.get({
  13 + url : url,
  14 + callbackParamName : 'callback',
  15 + content : { count : 10, format : 'json' },
  16 + load : dojo.hitch(this, function(data) {
  17 + dfd.resolve(dojo.map(data, function(t) {
  18 + return this._processTweet(t, username);
  19 + }, this));
  20 + })
  21 + });
  22 +
  23 + return dfd.promise;
  24 + },
  25 +
  26 + _processTweet : function(t, username) {
  27 + return {
  28 + text : t.text,
  29 + date : t.created_at,
  30 + url : [ 'http://twitter.com', username, 'status', t.id_str ].join('/')
  31 + };
  32 + }
  33 +};
50 www/js/app/services/YQL.js
... ... @@ -0,0 +1,50 @@
  1 +dojo.provide('app.services.YQL');
  2 +
  3 +dojo.require('dojo.io.script');
  4 +
  5 +app.services.YQL = {
  6 + _doQuery : function(config) {
  7 + dojo.io.script.get({
  8 + url : 'http://query.yahooapis.com/v1/public/yql',
  9 + callbackParamName : 'callback',
  10 + content : dojo.mixin({
  11 + format : 'json'
  12 + }, config.content),
  13 + load : config.load
  14 + });
  15 + },
  16 +
  17 + weather : function(location) {
  18 + var dfd = new dojo.Deferred();
  19 +
  20 + dojo.when(this.zip(location), dojo.hitch(this, function(zip) {
  21 + this._doQuery({
  22 + content : {
  23 + q : 'select * from weather.forecast where location=' + zip
  24 + },
  25 + load : function(data) {
  26 + console.log('loaded weather', data);
  27 + dfd.resolve(data.query.results.channel.item);
  28 + }
  29 + });
  30 + }));
  31 +
  32 + return dfd.promise;
  33 + },
  34 +
  35 + zip : function(location) {
  36 + var dfd = new dojo.Deferred();
  37 +
  38 + this._doQuery({
  39 + content : {
  40 + q : 'select * from geo.placefinder where text="' + location + '"'
  41 + },
  42 + load : function(data) {
  43 + console.log('loaded location data', data);
  44 + dfd.resolve(data.query.results.Result.uzip);
  45 + }
  46 + });
  47 +
  48 + return dfd.promise;
  49 + }
  50 +};
35 www/js/app/views/People.js
... ... @@ -0,0 +1,35 @@
  1 +dojo.provide('app.views.People');
  2 +
  3 +dojo.declare('app.views.People', [ dijit._Widget, dijit._Templated ], {
  4 + templateString : dojo.cache('app.views', 'People/People.html'),
  5 + personTemplate : dojo.cache('app.views', 'People/Person.html'),
  6 +
  7 + postMixInProperties : function() {
  8 + this.listHtml = dojo.map(this.people, function(p) {
  9 + return dojo.string.substitute(this.personTemplate, p.data);
  10 + }, this).join('');
  11 + },
  12 +
  13 + postCreate : function() {
  14 + this.connect(this.domNode, 'click', '_handleClick');
  15 + },
  16 +
  17 + _handleClick : function(e) {
  18 + var t = e.target,
  19 + id;
  20 +
  21 + if (t.nodeName.toLowerCase() !== 'li') { return; }
  22 +
  23 + dojo.forEach(this.domNode.children, function(c) {
  24 + dojo.removeClass(c, 'selected');
  25 + });
  26 +
  27 + dojo.addClass(t, 'selected');
  28 +
  29 + this.onSelect(dojo.attr(t, 'data-id'));
  30 + },
  31 +
  32 + onSelect : function(id) {
  33 + // stub for connection
  34 + }
  35 +});
3  www/js/app/views/People/People.html
... ... @@ -0,0 +1,3 @@
  1 +<ul class="people">
  2 + ${listHtml}
  3 +</ul>
1  www/js/app/views/People/Person.html
... ... @@ -0,0 +1 @@
  1 +<li data-id=${id}>${name}</li>
39 www/js/app/views/Person.js
... ... @@ -0,0 +1,39 @@
  1 +dojo.provide('app.views.Person');
  2 +
  3 +dojo.require('dijit._Widget');
  4 +dojo.require('dijit._Templated');
  5 +
  6 +dojo.declare('app.views.Person', [ dijit._Widget, dijit._Templated ], {
  7 + templateString : dojo.cache('app.views', 'Person/Person.html'),
  8 + tweetTemplate : dojo.cache('app.views', 'Person/Tweet.html'),
  9 + weatherTemplate : dojo.cache('app.views', 'Person/Weather.html'),
  10 +
  11 + // mark the weather and twitter areas as loading
  12 + postCreate : function() {
  13 + dojo.forEach([ 'latestTweet', 'olderTweets', 'weather' ], function(n) {
  14 + dojo.addClass(this[n], 'loading');
  15 + }, this);
  16 + },
  17 +
  18 + _setTweetsAttr : function(tweets) {
  19 + dojo.removeClass(this.olderTweets, 'loading');
  20 + dojo.removeClass(this.latestTweet, 'loading');
  21 +
  22 + var latest = tweets.shift();
  23 +
  24 + this.olderTweets.innerHTML = dojo.map(tweets, function(t) {
  25 + return dojo.string.substitute(this.tweetTemplate, t);
  26 + }, this).join('');
  27 +
  28 + this.latestTweet.innerHTML = dojo.string.substitute(
  29 + this.tweetTemplate, latest
  30 + );
  31 + },
  32 +
  33 + _setWeatherDataAttr : function(weather) {
  34 + dojo.removeClass(this.weather, 'loading');
  35 + this.weather.innerHTML = dojo.string.substitute(
  36 + this.weatherTemplate, weather
  37 + );
  38 + }
  39 +});
9 www/js/app/views/Person/Person.html
... ... @@ -0,0 +1,9 @@
  1 +<div class="person">
  2 + <h1><img src="${person.data.img}" alt="${person.data.name}">
  3 + ${person.data.name}</h2>
  4 + <ul class="latest-tweet" dojoAttachPoint="latestTweet"></ul>
  5 + <div class="info">
  6 + <ul class="twitter" dojoAttachPoint="olderTweets"></ul>
  7 + <div class="weather" dojoAttachPoint="weather"></div>
  8 + </div>
  9 +</div>
4 www/js/app/views/Person/Tweet.html
... ... @@ -0,0 +1,4 @@
  1 +<li>
  2 + <p class="tweet">${text}</p>
  3 + <p class="date"><a href="${url}">${date}</a></p>
  4 +</li>
4 www/js/app/views/Person/Weather.html
... ... @@ -0,0 +1,4 @@
  1 +<div>
  2 + <h3>${title}</h3>
  3 + <p>${description}</p>
  4 +</div>
13 www/js/app/views/Weather.js
... ... @@ -0,0 +1,13 @@
  1 +dojo.provide('app.views.Weather');
  2 +
  3 +dojo.require('dijit._Widget');
  4 +dojo.require('dijit._Templated');
  5 +dojo.require('app.services.YQL');
  6 +
  7 +dojo.declare('app.views.Weather', [ dijit._Widget, dijit._Templated ], {
  8 + templateString : dojo.cache('app.views', 'Weather/Weather.html'),
  9 +
  10 + postCreate : function() {
  11 + dojo.when(app.services.YQL.weather(this.location),
  12 + }
  13 +});

0 comments on commit b5af487

Please sign in to comment.
Something went wrong with that request. Please try again.