A Basic List

Displaying a list of items loaded from Facebook. requires the coordinated use of three classes: ui.widget.ListView, ui.widget.CellView, and GCDataSource.

Import device to get the screen size.

import device;

Import GCDataSource to store the items.

import GCDataSource;

Import the List and Cell classes to create a list.

import ui.widget.List as List;
import ui.widget.Cell as Cell;
import ui.widget.ButtonView as ButtonView;

import ui.TextView as TextView;
import ui.TextPromptView as TextPromptView;
import ui.View as View;

import util.ajax as ajax;

var COLOR1 = "rgb(59,89,152)";
var COLOR2 = "rgb(109,132,180)";
var COLOR3 = "rgb(205,216,234)";
var COLOR4 = "rgb(255,255,255)";
var COLOR5 = "rgb(175,189,212)";
var COLOR6 = "rgb(18,20,54)";

var startSearch = "learning";

var InfoDataSource = Class(GCDataSource, function (supr) {
	this.init = function (opts) {
		opts = merge(
			opts,
			{
				key: "id",
				reverse: true,

Sort by oldest last

				sorter: function (data) { return data.created_time; }
			}
		);

		supr(this, "init", [opts]);

		this._searchFor = startSearch;

		this.load();
	};

	this.load = function () {
		this.clear();
		this.emit("Clear");

Search Facebook

		ajax.get(
			{
				url: "http://graph.facebook.com/search",
				headers: {"Content-Type": "text/plain"},

This data will be added as query parameters

				data: {q: this._searchFor, type: "post"},

Parse the result as JSON

				type: "json"
			},

call onData when the search results are loaded

			bind(this, "onData")
		);
	};

Customize the sort function, add indices to the items after sorting

	this.sort = function () {
		supr(this, "sort");

		var i = this._byIndex.length;
		while (i) this._byIndex[--i].index = i;
	};

Prepend zeros to a string

	this._leadingZero = function (s, length) {
		s += "";
		while (s.length < length) s = "0" + s;
		return s;
	};

This callback is called when the data is loaded

	this.onData = function (err, response) {
		if (!err) {

Iterate over the list and parse the date

			for (var i = 0; i < response.data.length; i++) {
				var item = response.data[i];
				var date = new Date(item.created_time);

				item.posted = this._leadingZero(date.getHours(), 2) + ":" + this._leadingZero(date.getMinutes(), 2) + " - " +
					(date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear();
			}

Add the list to the data source

			this.add(response.data);

Sort the list

			this.sort();

Left the view know that the data is ready

			this.emit("Loaded");
		} else {

Something went wrong, publis the Error event so that a message can be displayed

			this.emit("Error");
		}
	};

Set the search string and load the data

	this.setSearchFor = function (searchFor) {
		this._searchFor = searchFor;
		this.load();
	};
});

Class: Application

Create an application, set the default properties.

exports = Class(GC.Application, function () {

	this.getCell = function () {
		var infoList = this._infoList;

		return new InfoCell({superview: infoList, infoData: this._infoData});
	};

	this.initUI = function () {
		this.style.backgroundColor = COLOR4;

Set up the datasource.

		this._infoData = new InfoDataSource();
		this._infoData.on("Clear", bind(this, "onClear"));
		this._infoData.on("Loaded", bind(this, "onLoaded"));
		this._infoData.on("Error", bind(this, "onError"));

		this._title = new TextView({
			superview: this,
			x: 0,
			y: 0,
			width: device.width,
			height: 50,
			size: 30,
			text: "Search Facebook",
			color: COLOR4,
			backgroundColor: COLOR1
		});

		this._loadingLabel = new TextView({
			superview: this,
			x: 0,
			y: 50,
			width: device.width,
			height: device.height - 100,
			size: 18,
			text: "Searching for: " + startSearch,
			color: COLOR6
		});

Create the List, which inherits from ScrollView.

		this._infoList = new List({
			superview: this.view,
			x: 0,
			y: 50,
			width: device.width,
			height: device.height - 100,

Use the dataSource:

			dataSource: this._infoData,
			selectable: "multi",
			maxSelections: 10,
			scrollX: false,
			getCell: bind(this, "getCell"),
			visible: false
		});

		this._searchLabel = new TextView({
			superview: this,
			x: 0,
			y: device.height - 50,
			width: device.width / 2,
			height: 50,
			size: 20,
			text: "search for:",
			horizontalAlign: "right",
			color: COLOR1,
			backgroundColor: COLOR5
		});
		this._searchLabel.onInputSelect = bind(this, "onSelectSeach");
		this._search = new TextPromptView({
			superview: this,
			x: device.width / 2,
			y: device.height - 50,
			width: device.width / 2,
			height: 50,
			size: 20,
			text: startSearch,
			horizontalAlign: "left",
			padding: [0, 0, 0, 6],
			color: COLOR1,
			backgroundColor: COLOR5,
			value: startSearch,
			prompt: "Enter a search term:"
		});
		this._search.on("Change", bind(this, "onChangeSearch"));
	};

This callback is called when the search label is clicked

	this.onSelectSeach = function () {
		this._search.showPrompt();
	};

When there’s a new text entered in the prompt dialog then this callback is called and Facebook is searched again

	this.onChangeSearch = function (value) {
		this._loadingLabel.setText("Searching for: " + value);
		this._infoData.setSearchFor(value);
	};

Something in the request went wrong

	this.onError = function () {
		this._loadingLabel.setText("Failed to load data");
	};

This function is called when a new search starts, the list is hidden and the searching message is shown

	this.onClear = function () {
		this._infoList.style.visible = false;
		this._loadingLabel.style.visible = true;
	};

This callback is called when the search data is loaded

	this.onLoaded = function () {
		this._infoList.style.visible = true;
		this._loadingLabel.style.visible = false;
	};

	this.launchUI = function () {};
});

Class: InfoCell

Subclass a Cell which is a view, it can have child views, and accepts data from a List.

var InfoCell = Class(Cell, function (supr) {
	this.init = function (opts) {
		this._infoData = opts.infoData;

		opts.width = device.width;
		opts.height = 75;

		supr(this, "init", [opts]);

The TextView showing who posted the message

		this._from = new TextView({
			superview: this,
			x: 10,
			y: 5,
			width: device.width - 20,
			height: 20,
			size: 13,
			horizontalAlign: "left",
			color: COLOR2
		});

The time and date when the message was posted

		this._posted = new TextView({
			superview: this,
			x: 10,
			y: 5,
			width: device.width - 20,
			height: 20,
			size: 13,
			horizontalAlign: "right",
			color: COLOR2
		});

The message

		this._message = new TextView({
			superview: this,
			x: 10,
			y: 25,
			width: device.width - 20,
			height: 47,
			size: 13,
			horizontalAlign: "left",
			verticalAlign: "top",
			wrap: true,
			autoFontSize: false,
			autoSize: false,
			clip: true,
			color: COLOR6
		});
	};

	this._toLength = function (s, length) {
		if (s.length > length) {
			var i = Math.max(0, length - 10);
			while (i < length - 1) {
				if (s[i] === " ") {
					break;
				}
				i++;
			}
			s = s.substr(0, i) + "...";
		}
		return s;
	};

	this.update = function () {
		var data = this._data;

Set the color depending on if it’s an even or odd row

		this.style.backgroundColor = ((data.index & 1) === 0) ? COLOR3 : COLOR4;

Show the first 40 characters of the name

		this._from.setText(this._toLength(data.from.name || "", 40));

Show the time and date

		this._posted.setText(data.posted);

Show the first 100 characters of the message

		this._message.setText(this._toLength(data.message || "", 100));
	};

Called when a cell is put on screen. We’ll use it to update our TextView child.

	this.setData = function (data) {
		this._data = data;
		this.update();
	};
});

Run this code in the simulator, and you should see something like the following screenshot. You can drag the list up and down, but not right or left. listview screenshot