Skip to content

Ecce Signum

Immanentize the Empathy

  • Home
  • About Me
  • Published Works and Literary Matters
  • Indexes
  • Laboratory
  • Notebooks
  • RSS Feed

New Things in the New Year

2015-01-02 John Winkelman

Coincident with the start of the New Year I have some new pursuits in my life. Well, one, actually. Maybe one and a half.

Back in November of 2013 I participated in National Novel Writing Month (“NaNoWriMo“) for the first time. I wrote just over 50,000 words in a near-future speculative fiction piece. In that time I joined a group of local writers. We call ourselves WriteOnGR. Within that group was a small cadre who had the idea/desire/drive to start a small publishing house which catered to writers who live in, or have some connection to, West Michigan.

Thus was born Caffeinated Press. We are a small publishing house. Each of us wears many hats.

Our first effort is an anthology of short stories, which we hope will hit the shelves sometime in February 2015. All the stories therein are completed and edited, and we are working on the design and layout of the actual book. Plus marketing, distribution, etc.

Caffeinated Press is now open for submissions. Any genre, any length.

It’s fun to participate in the beginning of something. That doesn’t happen so often any more.

 

Posted in Literary MattersTagged Caffeinated Press comment on New Things in the New Year

A Collection of Links Concerning Peter Matthiessen

2014-05-20 John Winkelman

Missouri Review interview, summer 1989

PBS Frontline episode “Lost Man’s River”, 1990 (video)

Paris Review interview with Peter Matthiessen, December 1997 (audio, video)

Paris Review interview, April 1999

Profile of Matthiessen at the Guardian, August 2002

Interview at the Writer’s Symposium by the Sea (Point Loma Nazarene University), April 2005 (video)

Penn State interview with Matthiessen, 2010 (video, transcript)

Excerpt from Ocean Fishes, in Sports Illustrated, August 2012

Los Angeles Review of Books interview, February 2014

Terry Gross remembers Peter Matthiessen, April 2014 (includes audio from 1989 interview)

“Peter Matthiessen’s Homegoing” New York Times article published just before his death in April 2014

Posted in Literary MattersTagged Peter Matthiessen comment on A Collection of Links Concerning Peter Matthiessen

Blandford Nature Center, 20 April, 2014

2014-05-16 John Winkelman

Middle of April. Warm enough in the morning to walk around in a sweater and Tilley hat. Hadn’t done that since, oh, sometime in October. What a relief to wander the woods relatively unencumbered! The animals felt it too; frogs, toads, snakes, turtles in abundance. And, of course, birds. Not much in the way of insects, though; not enough mass to store heat for more than a few moments. Anyway, here are a few photos. The rest are in an album here on Flickr.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1166″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Robin

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1171″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Goldfinch

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1176″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

The most boring chipmunk in West Michigan. Seriously. This little dude sat on that stump, mouth full of food, and didn’t move for at least a minute. Ain’t nobody got time for that!

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1181″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Shy garter snake.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1186″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Painted turtle.

Posted in Photography comment on Blandford Nature Center, 20 April, 2014

Seidman Park, March 30, 2014

2014-05-13 John Winkelman

By the end of March the thaw had begun. Temperatures were up and the vast piles of snow were diminishing rapidly. But we had SO much snow that the thaw was (and is) a long, ongoing process. Seidman Park, one of my favorite haunts, was more white than brown or green; but it was still a beautiful day, and a beautiful walk.

I get the sense that the animals in Michigan are a little stunned from the winter.

Some photos here, the rest in their own set over at Flickr.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1191″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Seidman Park, out in the woods.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1196″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Snow melt creates a temporary stream across the trail.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1201″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Deer trail. I imagine the extreme winter and deep snow caused deer to concentrate along more established trails; thus the large amount of deer pellet trails in the forest. I expect that, come summer, there will be long intersecting lines of particularly healthy plants.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1206″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

One of several turkey feathers I found during my walk. Someone got lucky. Someone else didn’t.

Posted in Photography comment on Seidman Park, March 30, 2014

Butterflies at the Frederick Meijer Gardens

2014-05-09 John Winkelman

On March 15 I visited the Frederik Meijer Gardens with my good friend Andrea, to take in the warmth and butterflies of the arboretum. If you have never been, I recommend the experience. After a winter like that of 2013-2014, any warmth is welcome, and a tropical rain forest is the perfect getaway. Only down side: more people than butterflies. If you can choose a time, go in the morning, preferrably on a weekday. No line to speak of, and fewer people in general. Afternoon on a Saturday is kind of crazy. Anyway: here are some photos. The full set is here on Flickr.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1211″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Red Passion Flower butterfly. Good name.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1216″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

“Paper Kite” butterfly. And when you see them flying around…yeah, they kind of do look like they fit the name.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1221″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

This one fluttered a little too low.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1226″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Emerald Swallowtail. I think this is my favorite of the butterflies on display.

 

Posted in Photography comment on Butterflies at the Frederick Meijer Gardens

A Collection of Links Concerning Ted Kooser

2014-05-05 John Winkelman

This is a list of interviews, articles, and talks, and readings about and with American Poet Laureate Ted Kooser.

Ted Kooser on NPR’s All Things Considered, October 2005. (Audio and article)

The Crossing Over; Interview with Kooser for Guernica Magazine, April 2006

Kooser visits University of California, Davis, October 2006. (video)

Poetry reading on UCTV, January 2008 (video)

Sally Molini interview Kooser for the Summer 2009 issue of Cerise Press.

Interview with Ted Kooser for Shenandoah, January 2012.

Posted in Literary MattersTagged Ted Kooser comment on A Collection of Links Concerning Ted Kooser

Duck Lake State Park, February 16, 2014

2014-05-03 John Winkelman

On February 16, feeling like I just wasn’t cold enough, I drove out to Duck Lake State Park and wandered around the lakeshore for a couple of hours. It was a beautiful day, though very cold, and Muskegon County had at that point had a lot of snow. So the walk was also an adventure. Anyway; here are some of the photos. The entire set is posted here on Flickr.

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1146″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Duck Creek at Duck Lake State Park

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1151″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Lake Michigan at Duck Lake State Park

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1156″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Red Breasted Merganser

[[{“type”:”media”,”view_mode”:”media_original”,”fid”:”1161″,”attributes”:{“alt”:””,”class”:”media-image”,”height”:”480″,”typeof”:”foaf:Image”,”width”:”640″}}]]

Ice formation out on the water. This is caused by air pushing up through cracks in the ice. As water is warmer than the ice, it is continually added to the mound, like magma forming and shaping a volcano.

Posted in Photography comment on Duck Lake State Park, February 16, 2014

Simple Backbone Marionette Example With AppRouter

2014-05-02 John Winkelman

This one took a little longer than the rest to put together, because I nearly broke my brain trying to figure out how routing worked. I found myriad code samples for setting up and using the router, but no one sample had everything I needed to put together a bare-bones app. Once i finally figured it out, the rest snapped together immediately. So without further ado – First, the Javascript file:

/* define the application */
var app = new Backbone.Marionette.Application();

/* add the main region to the application */
app.addRegions({
	appRegion: '#AppBase'
});

/* define the module we will be using to create this app */
app.module('RouteTest',function(module, App, Backbone, Marionette, $, _){
	"use strict";

	/* the layout for the main view */
	module.AppLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'AppLayoutView',
		template: '#template-AppLayoutView',

		regions: {
			'contentRegion' : '#ContentRegion'
		},
		ui: {
			'navHome' : '#nav-home',
			'navInfo' : '#nav-info'
		},
		events: {
			'click #nav-home' : 'onNavHomeClicked',
			'click #nav-info' : 'onNavInfoClicked'
		},

		/* when the view initializes, call initRouter to */
		initialize: function() {
			this.initRouter();
		},

		/* once the DOM is ready, start the Backbone history manager.
			This will cause the application to synch up with the 
			current route of the browser, e.g. #home or #info.
			This must be called onRender instead of on initialize
			because it immediately tries to render the appropriate view
			into the contentRegion. Also: If you don't start the backbone
			history, the router won't work. */
		onRender: function() {
			if( ! Backbone.History.started) Backbone.history.start();
		},

		/* initialize the AppRouter, which synchs the application
			to the browser navigation */
		initRouter: function() {

			// cache reference to 'this' in the module scope
			var capturedThis = this;

			// assign route handlers to specific routes.
			// In this case, 'home' is triggered when the browser
			// visits index.html#home. Likewise index.html#info.
			// the empty set is for an address with no hash.
			var appRouteHandler = {
					'' : 'onHomeRoute',
				'home' : 'onHomeRoute',
				'info' : 'onInfoRoute'
			}

			// controller which contains the methods which
			// are used as route handlers. These are referenced
			// in the appRoutes object above.
			var appRouterController = {
				onHomeRoute: function() {
					capturedThis.onHomeNavigated();
				},
				onInfoRoute: function() {
					capturedThis.onInfoNavigated();
				}
			};

			// define an AppRouter constructor
			var router = Marionette.AppRouter.extend({});

			// create a new instance of the AppRouter
			// and assign the routes and controller
			var appRouter = new router({
				appRoutes: appRouteHandler, 
				controller: appRouterController
			});
		},

		/* called when the router sees that we have met the criteria
			to trigger the 'onHomeRoute' handler */
		onHomeNavigated: function() {

			// define and display an instance of the HomeLayoutView
			var homeLayoutView = new module.HomeLayoutView();
			this.contentRegion.show(homeLayoutView);

			// update the navigation
			this.$el.find('.navButton.active').removeClass('active');
			this.ui.navHome.addClass('active');
		},

		/* called when the router sees that we have met the criteria
			to trigger the 'onInfoRoute' handler */
		onInfoNavigated: function() {
			var infoLayoutView = new module.InfoLayoutView();
			this.contentRegion.show(infoLayoutView);
			this.$el.find('.navButton.active').removeClass('active');
			this.ui.navInfo.addClass('active');
		}
	});

	/* view definition for the 'Home' screen */
	module.HomeLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'HomeLayoutView',
		className: 'contentLayout',
		template: '#template-HomeLayoutView'
	});

	/* view definition for the 'Info' screen */
	module.InfoLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'InfoLayoutView',
		className: 'contentLayout',
		template: '#template-InfoLayoutView'
	});

	/* add initializer, which fires when the app starts */
	module.addInitializer(function(){
		var layout = new module.AppLayoutView();

		/* show the layout in the region we created at the top of this file */
		app.appRegion.show(layout);
	});
});

/* when the DOM for this page is available, start the application */
$(document).ready(function() {
	app.start();
});

And here is the HTML file, including the templates.

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette Routing Example Using AppRouter</title>
		<style type="text/css">
			body {
				background: #ffffff;
			}
			#AppBase {
				width: 600px;
				margin: 10px auto;
				padding: 0;
			}
			#AppLayoutView {
				float: left;
				width: 598px;
				margin: 0;
				padding: 0;
				border: 1px solid #808080;
			}
			h1 {
				margin: 0;
				padding: 0;
				float: left;
				width: 100%;
				height: 30px;
				text-align: center;
				font: 24px/30px courier;
			}
			#Navigation {
				float: left;
				width: 100%;
				height: 30px;
				background: #ededed;
				text-align: center;
			}
			#Navigation a {
				font: 16px/30px courier, monospace;
				color: #000000;
				text-decoration: none;
			}
			#Navigation .navButton.active {
				color: #ff0000;
			}
			#ContentRegion {
				float: left;
				width: 100%;
			}
			.contentLayout {
				float:left;
				width: 100%;
				margin: 0;
				padding: 0;
				
			}
			#HomeLayoutView {
				background: #edffed;
			}
			#InfoLayoutView {
				background: #ededff;
			}
			.contentLayout h2 {
				margin: 0;
				padding: 0;
				text-align: center;
				border-bottom: 1px solid #808080;
				background: #ffffff;
			}
			.contentLayout p {
				padding: .5em 1em;
			}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<div id="AppBase"></div>

		<!-- main layout template -->
		<script type="text/template" id="template-AppLayoutView">
			<h1>Backbone/Marionette Routing Example</h1>
			<div id="Navigation">
				<a id="nav-home" class="navButton" href="#home">Home</a> : : : 
				<a id="nav-info" class="navButton" href="#info">Information</a>
			</div>
			<div id="ContentRegion">HELLO!</div>
		</script>

		<!-- home screen template -->
		<script type="text/template" id="template-HomeLayoutView">
			<h2>Home</h2>
			<p>This is the home view</p>
		</script>

		<!-- info screen template -->
		<script type="text/template" id="template-InfoLayoutView">
			<h2>Information</h2>
			<p>This is a page of information</p>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

By the way, the missing piece which ended up costing me the better part of a day was the Backbone.history.start() call in the onRender method in the main Layout view.

Posted in Programming comment on Simple Backbone Marionette Example With AppRouter

More On Using Google Spreadsheets and Backbone/Marionette

2014-04-06 John Winkelman

Pulling data from a published Google Spreadsheet it actually quite simple. All you need is a spreadsheet which you have “published to web”; i.e. made visible (but not editable) to the public. Backbone models have no difficulty pulling the data in, but the structure is complex, and requires a little explanation.

First, here is what the spreadsheet looks like:

Name per square foot height
arugula 9 9
basil 4 9
beets 9 6
carrots 16 4
collard greens 2 16
cauliflower 1 18
tomatoes 1 36
broccoli 1 24
mustard greens 9 12
peppers 1 18
chard 4 12
kale 2 12
radish 36 8
brussels sprouts 1 24
okra 1 24
eggplant 1 24
celery 4 18

I am pulling in a representational JSON feed from Google Drive. The data (trimmed to the first two rows) looks something like this:

{
	"version": "1.0",
	"encoding": "UTF-8",
	"feed": {
		"xmlns": "http://www.w3.org/2005/Atom",
		"xmlns$openSearch": "http://a9.com/-/spec/opensearchrss/1.0/",
		"xmlns$gsx": "http://schemas.google.com/spreadsheets/2006/extended",
		"id": {
			"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values"
		},
		"updated": {
			"$t": "2014-01-22T19:27:16.240Z"
		},
		"category": [
			{
				"scheme": "http://schemas.google.com/spreadsheets/2006",
				"term": "http://schemas.google.com/spreadsheets/2006#list"
			}
		],
		"title": {
			"type": "text",
			"$t": "Sheet1"
		},
		"link": [
			{
				"rel": "alternate",
				"type": "text/html",
				"href": "https://spreadsheets.google.com/pub?key={{DOCUMENT_KEY}}"
			},
			{
				"rel": "http://schemas.google.com/g/2005#feed",
				"type": "application/atom+xml",
				"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values"
			},
			{
				"rel": "self",
				"type": "application/atom+xml",
				"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values?alt=json-in-script"
			}
		],
		"author": [
			{
				"name": {
					"$t": "user.name"
				},
				"email": {
					"$t": "user.name@gmail.com"
				}
			}
		],
		"openSearch$totalResults": {
			"$t": "17"
		},
		"openSearch$startIndex": {
			"$t": "1"
		},
		"entry": [
			{
				"id": {
					"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
				},
				"updated": {
					"$t": "2014-01-22T19:27:16.240Z"
				},
				"category": [
					{
						"scheme": "http://schemas.google.com/spreadsheets/2006",
						"term": "http://schemas.google.com/spreadsheets/2006#list"
					}
				],
				"title": {
					"type": "text",
					"$t": "arugula"
				},
				"content": {
					"type": "text",
					"$t": "persquarefoot: 9, height: 9"
				},
				"link": [
					{
						"rel": "self",
						"type": "application/atom+xml",
						"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
					}
				],
				"gsx$name": {
					"$t": "arugula"
				},
				"gsx$persquarefoot": {
					"$t": "9"
				},
				"gsx$height": {
					"$t": "9"
				}
			},
			{
				"id": {
					"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
				},
				"updated": {
					"$t": "2014-01-22T19:27:16.240Z"
				},
				"category": [
					{
						"scheme": "http://schemas.google.com/spreadsheets/2006",
						"term": "http://schemas.google.com/spreadsheets/2006#list"
					}
				],
				"title": {
					"type": "text",
					"$t": "basil"
				},
				"content": {
					"type": "text",
					"$t": "persquarefoot: 4, height: 9"
				},
				"link": [
					{
						"rel": "self",
						"type": "application/atom+xml",
						"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
					}
				],
				"gsx$name": {
					"$t": "basil"
				},
				"gsx$persquarefoot": {
					"$t": "4"
				},
				"gsx$height": {
					"$t": "9"
				}
			}
		]
	}
}

It’s a lot of information, but it is fairly simply laid out. There is a lot of meta-data and author information. For the purposes of a simple display list, the only data we need is the ‘entries’ array. This is an array of Javascript objects, each of which represents a row in the spreadsheet. This assumes that the first row in the spreadsheet contains the titles for each column; e.g. ‘name’, ‘per square foot’, etc.

Note that within each of the entries in the array are three objects which correspond to the columns in the spreadsheet: gsx$name, gsx$persquarefoot, and gsx$height. These are simply the names of the columns, stripped of spaces and converted to all lower case. Each of these objects contains a single object with the key ‘$t’, which has a value equal to the content of the corresponding cell from the spreadsheet.

If you review the code from my previous post you can see that, once the data structure is known, it is quite simple to parse the JSON for the values you need.

Note also that this entry does not address the process of modifying a Google Spreadsheet from outside of the Google Drive context; that is a significantly more complex operation.

Posted in Programming comment on More On Using Google Spreadsheets and Backbone/Marionette

Backbone/Marionette App Pulling Data From Google Spreadsheet

2014-03-09 John Winkelman

Here is an example of a simple display application pulling data from a publicly available Google spreadsheet. It parses the data into a usable form and displays it in a sortable table using a Marionette.js Composite View.

The methods used, and pitfalls inherent, in pulliing a JSON feed from a Google spreadsheet warrant their own post, which will happen in the near future. In the meantime, here is the code for this app. First the Javascript:

/* define the application */
var app = new Backbone.Marionette.Application();

/* add the main region to the application */
app.addRegions({
	appRegion: '#AppBase'
});

/* define the module we will be using to create this app */
app.module('Garden',function(module, App, Backbone, Marionette, $, _){
	"use strict";

	/* the URL for the JSON feed from the Google Spreadsheep */
	module.spreadsheetKey = '0AtrrbpAB-ITbdFFXVklRbHZUVW5kX2F1UWVKVVBfOVE'; // a sample spreadsheet in google docs
	module.spreadsheetURL = 'https://spreadsheets.google.com/feeds/list/{{KEY}}/od6/public/values?alt=json-in-script&callback=?';

	/* model for an individual item */
	module.GardenModel = Backbone.Model.extend({
		/* the URL from which the data is pulled */
		url: module.spreadsheetURL.split('{{KEY}}').join(module.spreadsheetKey),

		/* take the data retrieved from the URL, go through it looking for only
			the data we actually need, and pull it out and format it. This is 
			necessary because the data returned by Google Spreadsheets
			is a cumbersome mess. */
		parse: function(data) {
			var parsedArray = [];

			/* use Underscore to iterate through each item in the feed,
				and pull out the necessary fields and put them in an
				array of anonymous objects which will be returned
				as the main model for this application */
			_.each(data.feed.entry,function(oItem) {
				parsedArray.push({
					name: oItem['gsx$name']['$t'],
					perSquareFoot: parseInt(oItem['gsx$persquarefoot']['$t']),
					height: parseFloat(oItem['gsx$height']['$t'])
				});
			});
			return ({dataset:parsedArray});
		}
	});

	module.PlantModel = Backbone.Model.extend({
		defaults: {
			name: '',
			perSquareFoot: 1,
			height: 1
		}
	});

	module.PlantCollection = Backbone.Collection.extend({
		model: module.PlantModel,

		/* initial field used to sort the models when the collection is displayed */
		comparator: 'name'
	});

	/* individual item view for each model in the collection */
	module.PlantItemView = Marionette.ItemView.extend({
		tagName: 'tr',
		template: '#row-template'
	});

	/* Composite View for displaying tabular data. Composite Views
		allow more complex HTML to be used when rendering a template */
	module.PlantCompositeView = Marionette.CompositeView.extend({
		tagName: 'table',
		itemView: module.PlantItemView,

		/* the element in the template which will serve as the container for the ItemViews */
		itemViewContainer: 'tbody',
		template: '#table-template',

		/* add mouse events */
		events: {
			'click th' : 'onHeaderClicked'
		},
		
		/* called when one of the table headers is clicked. 
			Pulls the value of the 'data-sort' attribute on the element
			and uses that as the sort argument in the collection */
		onHeaderClicked: function(event){
			this.collection.comparator = $(event.target).data('sort');
			this.collection.sort();
			this.render();
		}
	});

	/* main layout for the application */
	module.GardenLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'AppContainer',
		template: '#layout-template',
		regions: {
			ListRegion: '#ListRegion'
		},

		/* called when the DOM for this view is available */
		onRender: function(){

			/* create a new collection based on the model fed into this view
				when it was created */
			var plantCollection = new module.PlantCollection(this.model.get('dataset'));

			/* create the new Composite View based on the collection*/
			var plantCompositeView = new module.PlantCompositeView({collection: plantCollection});

			/* display the composite view */
			this.ListRegion.show(plantCompositeView);
		}
	});

	/* add initializer, which fires when the app starts */
	module.addInitializer(function(){

		/* create a new instance of GardenModel */
		var baseModel = new module.GardenModel();

		/* create a local reference to 'this', which can be used in asynchronous callbacks */
		var capturedThis = this;

		/* load the data into the model */
		baseModel.fetch()
			.fail(function() {
				debugger;
			})
			.done(function() {
				/* on successfully loading the data, create a new instance of the main layout view,
					and feed the model into it. */
				var layout = new module.GardenLayoutView({model: baseModel});

				/* show the layout in the region we created at the top of this file */
				app.appRegion.show(layout);
			});
	});

});

/* when the DOM for this page is available, start the application */
$(document).ready(function() {app.start();});

And now the HTML and CSS

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette using data from Google Spreadsheet rendered in a Composite View</title>
		<style type="text/css">
			body {
				background: #ffffff;
			}
			#AppBase {
				width: 600px;
				margin: 10px auto 0 auto;
				padding: 0;
			}
			h1 {
				font: bold 16px/24px arial, sans-serif;
				text-align: center;
			}
			table {
				width: 600px;
				border-collapse: collapse;
			}
			th {
				font: 14px/18px courier;
				width: 200px;
				text-align: center;
				border: 1px solid #808080;
				background: #ededed;
				cursor: pointer;
			}
			th:hover {
				background: #cdcdcd;
				color: #990000;
			}
			td {
				font: 14px/18px courier;
				width: 200px;
				border: 1px solid #808080;
			}
			tfoot td {
				width: 600px;
				text-align: center;
			}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Dont use the BODY element as the base because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up 
		-->
		<div id="AppBase"></div>

		<!-- TEMPLATES -->
		<!-- table row template -->
		<script type="text/template" id="row-template">
			<td><%- name %></td>
			<td><%- perSquareFoot %></td>
			<td><%- height %></td>
		</script>

		<!-- table body template for composite view -->
		<script type="text/template" id="table-template">
			<thead>
				<tr>
					<th data-sort="name">Name</th>
					<th data-sort="perSquareFoot">Per Square Foot</th>
					<th data-sort="height">Height</th>
				</tr>
			</thead>
			<tbody></tbody>
			<tfoot>
				<td colspan="3">Click column headers to sort table</td>
			</tfoot>
		</script>

		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>Backbone/Marionette Application Which Retrieves Data From a Google Spreadsheet and Displays It In a Sortable Composite View</h1>
			<div id="ListRegion"></div>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

Here are links to the code libraries used in this app:

  • jQuery.js
  • Underscore.js
  • Backbone.js
  • Marionette.js
Posted in Programming comment on Backbone/Marionette App Pulling Data From Google Spreadsheet

Posts navigation

Older posts
Newer posts

Personal website of
John Winkelman

John Winkelman in closeup

Archives

Categories

Posts By Month

July 2025
S M T W T F S
 12345
6789101112
13141516171819
20212223242526
2728293031  
« Jun    

Links of Note

Reading, Writing
Tor.com
Locus Online
The Believer
File 770
IWSG

Watching, Listening
Writing Excuses Podcast
Our Opinions Are Correct
The Naropa Poetics Audio Archive

News, Politics, Economics
Naked Capitalism
Crooked Timber

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

© 2025 Ecce Signum

Proudly powered by WordPress | Theme: x-blog by wpthemespace.com