update countries example
This commit is contained in:
parent
d95d13f13d
commit
6e0b496852
1 changed files with 162 additions and 12 deletions
|
@ -1,12 +1,20 @@
|
||||||
/*
|
/*
|
||||||
In this example, we will build a list of countries that can be displayed in grid
|
In this example, we will build a list of countries that can be displayed both as
|
||||||
or list view.
|
a table and as a grid of icons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
Ox.load(['Geo', 'UI'], function() {
|
/*
|
||||||
|
We load the `UI` and `Geo` modules. The `Geo` module gives us Ox.COUNTRIES, the
|
||||||
|
data for our list.
|
||||||
|
*/
|
||||||
|
Ox.load(['UI', 'Geo'], function() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
We extend the country data to include a flag icon (Ox.getFlagByCountryCode
|
||||||
|
returns an image URL), and patch the `region` property so that when our list
|
||||||
|
is sorted by region, regions will be grouped by continent.
|
||||||
|
*/
|
||||||
var items = Ox.COUNTRIES.map(function(country) {
|
var items = Ox.COUNTRIES.map(function(country) {
|
||||||
return Ox.extend({}, country, {
|
return Ox.extend({}, country, {
|
||||||
flag: Ox.getFlagByCountryCode(country.code, 256),
|
flag: Ox.getFlagByCountryCode(country.code, 256),
|
||||||
|
@ -14,6 +22,12 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/*
|
||||||
|
These are the table columns in list view. The `operator` property
|
||||||
|
specifies the default sort order, `format` allows us to modify the value
|
||||||
|
before it gets displayed, `align` (default: `'left'`) is used to set the
|
||||||
|
alignment, and the rest should be pretty self-explanatory.
|
||||||
|
*/
|
||||||
columns = [
|
columns = [
|
||||||
{
|
{
|
||||||
id: 'code',
|
id: 'code',
|
||||||
|
@ -59,10 +73,10 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
width: 112
|
width: 112
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
align: 'right',
|
||||||
format: function(value) {
|
format: function(value) {
|
||||||
return Ox.formatDegrees(value, 'lat');
|
return Ox.formatDegrees(value, 'lat');
|
||||||
},
|
},
|
||||||
align: 'right',
|
|
||||||
id: 'lat',
|
id: 'lat',
|
||||||
operator: '-',
|
operator: '-',
|
||||||
title: 'Latitude',
|
title: 'Latitude',
|
||||||
|
@ -70,10 +84,10 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
width: 80
|
width: 80
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
align: 'right',
|
||||||
format: function(value) {
|
format: function(value) {
|
||||||
return Ox.formatDegrees(value, 'lng');
|
return Ox.formatDegrees(value, 'lng');
|
||||||
},
|
},
|
||||||
align: 'right',
|
|
||||||
id: 'lng',
|
id: 'lng',
|
||||||
operator: '+',
|
operator: '+',
|
||||||
title: 'Longitude',
|
title: 'Longitude',
|
||||||
|
@ -82,25 +96,59 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the width of the UI element where more information about the
|
||||||
|
selected item gets displayed.
|
||||||
|
*/
|
||||||
itemSize = 288 + Ox.UI.SCROLLBAR_SIZE,
|
itemSize = 288 + Ox.UI.SCROLLBAR_SIZE,
|
||||||
|
|
||||||
|
/*
|
||||||
|
`ui` holds the state of our application:
|
||||||
|
*/
|
||||||
ui = {
|
ui = {
|
||||||
|
/*
|
||||||
|
the query string,
|
||||||
|
*/
|
||||||
find: '',
|
find: '',
|
||||||
|
/*
|
||||||
|
the types of countries to include,
|
||||||
|
*/
|
||||||
include: {
|
include: {
|
||||||
dependency: false,
|
dependency: false,
|
||||||
disputed: false,
|
disputed: false,
|
||||||
dissolved: false,
|
dissolved: false,
|
||||||
exception: false
|
exception: false
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
|
the selected items (note that this is an array, even though we will
|
||||||
|
limit the maximum number of selected items to 1, later on),
|
||||||
|
*/
|
||||||
selected: [],
|
selected: [],
|
||||||
|
/*
|
||||||
|
the sort order (note that this is an array too, so if our country
|
||||||
|
names weren't unique, we could add more criteria)
|
||||||
|
*/
|
||||||
sort: [{key: 'name', operator: '+'}],
|
sort: [{key: 'name', operator: '+'}],
|
||||||
|
/*
|
||||||
|
and the view (either `'grid'` or `'list'`).
|
||||||
|
*/
|
||||||
view: 'grid'
|
view: 'grid'
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is the query for our list, which depends on `ui.find` and
|
||||||
|
`ui.include`.
|
||||||
|
*/
|
||||||
query = getQuery(),
|
query = getQuery(),
|
||||||
|
|
||||||
|
/*
|
||||||
|
A simple toolbar.
|
||||||
|
*/
|
||||||
$toolbar = Ox.Bar({size: 24}).addClass('bar'),
|
$toolbar = Ox.Bar({size: 24}).addClass('bar'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
A group of two buttons to switch between `grid` and `list` view.
|
||||||
|
*/
|
||||||
$view = Ox.ButtonGroup({
|
$view = Ox.ButtonGroup({
|
||||||
buttons: [
|
buttons: [
|
||||||
{id: 'grid', title: 'grid', tooltip: 'View as Grid'},
|
{id: 'grid', title: 'grid', tooltip: 'View as Grid'},
|
||||||
|
@ -113,6 +161,11 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
.bindEvent({change: view})
|
.bindEvent({change: view})
|
||||||
.appendTo($toolbar),
|
.appendTo($toolbar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
A select element to set the sort order. In `list` view, the table
|
||||||
|
provides its own UI for sorting, so we only show this element in `grid`
|
||||||
|
view.
|
||||||
|
*/
|
||||||
$sort = Ox.Select({
|
$sort = Ox.Select({
|
||||||
items: columns.filter(function(column) {
|
items: columns.filter(function(column) {
|
||||||
return column.id != 'flag';
|
return column.id != 'flag';
|
||||||
|
@ -129,13 +182,20 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
[ui.view == 'grid' ? 'show' : 'hide']()
|
[ui.view == 'grid' ? 'show' : 'hide']()
|
||||||
.appendTo($toolbar),
|
.appendTo($toolbar),
|
||||||
|
|
||||||
$order = Ox.Button(Ox.extend(getOptions(), {
|
/*
|
||||||
type: 'image'
|
A button to switch between 'ascending' and 'descending'. Again, this is
|
||||||
}))
|
only needed in `grid` view.
|
||||||
|
*/
|
||||||
|
$order = Ox.Button(getOptions())
|
||||||
.bindEvent({click: order})
|
.bindEvent({click: order})
|
||||||
[ui.view == 'grid' ? 'show' : 'hide']()
|
[ui.view == 'grid' ? 'show' : 'hide']()
|
||||||
.appendTo($toolbar),
|
.appendTo($toolbar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is our search box. To implement "find-as-you-type", we set its
|
||||||
|
`changeOnKeypress` option to `true`. Otherwise, its change event would
|
||||||
|
only fire when the user hits return.
|
||||||
|
*/
|
||||||
$find = Ox.Input({
|
$find = Ox.Input({
|
||||||
changeOnKeypress: true,
|
changeOnKeypress: true,
|
||||||
clear: true,
|
clear: true,
|
||||||
|
@ -146,6 +206,9 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
.bindEvent({change: find})
|
.bindEvent({change: find})
|
||||||
.appendTo($toolbar),
|
.appendTo($toolbar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
And a menu to specify which types of countries to include.
|
||||||
|
*/
|
||||||
$include = Ox.MenuButton({
|
$include = Ox.MenuButton({
|
||||||
items: [
|
items: [
|
||||||
{id: 'dependency', title: 'Include dependencies'},
|
{id: 'dependency', title: 'Include dependencies'},
|
||||||
|
@ -161,12 +224,24 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
.bindEvent({change: include})
|
.bindEvent({change: include})
|
||||||
.appendTo($toolbar),
|
.appendTo($toolbar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
The list itself.
|
||||||
|
*/
|
||||||
$list = renderList(),
|
$list = renderList(),
|
||||||
|
|
||||||
|
/*
|
||||||
|
A simple statusbar.
|
||||||
|
*/
|
||||||
$statusbar = Ox.Bar({size: 16}),
|
$statusbar = Ox.Bar({size: 16}),
|
||||||
|
|
||||||
|
/*
|
||||||
|
An element for the status text.
|
||||||
|
*/
|
||||||
$status = Ox.Element().addClass('status').appendTo($statusbar),
|
$status = Ox.Element().addClass('status').appendTo($statusbar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
The list panel holds the toolbar, the list and the statusbar.
|
||||||
|
*/
|
||||||
$listPanel = Ox.SplitPanel({
|
$listPanel = Ox.SplitPanel({
|
||||||
elements: [
|
elements: [
|
||||||
{element: $toolbar, size: 24},
|
{element: $toolbar, size: 24},
|
||||||
|
@ -176,14 +251,23 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/*
|
||||||
|
Now we can move on to the item panel. The first element is another bar.
|
||||||
|
*/
|
||||||
$titlebar = Ox.Bar({size: 24}).addClass('bar'),
|
$titlebar = Ox.Bar({size: 24}).addClass('bar'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
The label will show the country name.
|
||||||
|
*/
|
||||||
$title = Ox.Label({
|
$title = Ox.Label({
|
||||||
width: itemSize - 28
|
width: itemSize - 28
|
||||||
})
|
})
|
||||||
.hide()
|
.hide()
|
||||||
.appendTo($titlebar),
|
.appendTo($titlebar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
A button to deselect the currently selected item.
|
||||||
|
*/
|
||||||
$deselect = Ox.Button({
|
$deselect = Ox.Button({
|
||||||
title: 'close',
|
title: 'close',
|
||||||
type: 'image'
|
type: 'image'
|
||||||
|
@ -197,8 +281,15 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
.hide()
|
.hide()
|
||||||
.appendTo($titlebar),
|
.appendTo($titlebar),
|
||||||
|
|
||||||
|
/*
|
||||||
|
An element to hold the item data.
|
||||||
|
*/
|
||||||
$item = Ox.Element().addClass('item'),
|
$item = Ox.Element().addClass('item'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
The item panel: titlebar, item and one more bar (to match the layout of
|
||||||
|
the list panel).
|
||||||
|
*/
|
||||||
$itemPanel = Ox.SplitPanel({
|
$itemPanel = Ox.SplitPanel({
|
||||||
elements: [
|
elements: [
|
||||||
{element: $titlebar, size: 24},
|
{element: $titlebar, size: 24},
|
||||||
|
@ -208,6 +299,10 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/*
|
||||||
|
And finally the main panel, which combines the list panel and the item
|
||||||
|
panel.
|
||||||
|
*/
|
||||||
$mainPanel = Ox.SplitPanel({
|
$mainPanel = Ox.SplitPanel({
|
||||||
elements: [
|
elements: [
|
||||||
{element: $listPanel},
|
{element: $listPanel},
|
||||||
|
@ -217,6 +312,10 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
})
|
})
|
||||||
.appendTo(Ox.$body);
|
.appendTo(Ox.$body);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Whenever the user types something in the search box, we update the list
|
||||||
|
query.
|
||||||
|
*/
|
||||||
function find() {
|
function find() {
|
||||||
ui.find = $find.options('value');
|
ui.find = $find.options('value');
|
||||||
query = getQuery();
|
query = getQuery();
|
||||||
|
@ -224,14 +323,26 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
$list.options({query: query});
|
$list.options({query: query});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function returns the options for the sort order button, which depend on
|
||||||
|
`ui.sort`.
|
||||||
|
*/
|
||||||
function getOptions() {
|
function getOptions() {
|
||||||
var operator = ui.sort[0].operator;
|
var operator = ui.sort[0].operator;
|
||||||
return {
|
return {
|
||||||
title: operator == '+' ? 'up' : 'down',
|
title: operator == '+' ? 'up' : 'down',
|
||||||
tooltip: operator == '+' ? 'Ascending' : 'Descending'
|
tooltip: operator == '+' ? 'Ascending' : 'Descending',
|
||||||
|
type: 'image'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This function returns a query, which is an array of conditions and an
|
||||||
|
operator. Additionally to `find`, which applies to the country's name
|
||||||
|
property, we add a condition for each `include` setting that is `false`. For
|
||||||
|
example, in order to not include dependencies, we have to add a condition
|
||||||
|
that tests if the country's `dependency` property is `undefined`.
|
||||||
|
*/
|
||||||
function getQuery() {
|
function getQuery() {
|
||||||
var query = {
|
var query = {
|
||||||
conditions: [{key: 'name', operator: '=', value: ui.find}],
|
conditions: [{key: 'name', operator: '=', value: ui.find}],
|
||||||
|
@ -245,11 +356,24 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A handler for the `change` event of the menu button.
|
||||||
|
*/
|
||||||
function include(data) {
|
function include(data) {
|
||||||
ui.include[data.id] = data.checked;
|
ui.include[data.id] = data.checked;
|
||||||
find();
|
find();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A handler for the `init` event of the list, which fires once the list knows
|
||||||
|
the total number of items for the current query. In our case, it'll know
|
||||||
|
that instantly. But the list's `items` option doesn't have to be a static
|
||||||
|
array — it can also be a call to any remote API that understands our
|
||||||
|
`query` syntax. (In fact, when passing an `items` array, Ox.List uses
|
||||||
|
Ox.api, which is a local implementation of such an API.) The first request
|
||||||
|
to this API will return the totals, so they can be displayed before
|
||||||
|
retrieving the actual data.
|
||||||
|
*/
|
||||||
function init(data) {
|
function init(data) {
|
||||||
$status.html(
|
$status.html(
|
||||||
(data.items || 'No') + ' countr'
|
(data.items || 'No') + ' countr'
|
||||||
|
@ -257,12 +381,24 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A handler for the `click` event of the sort order button. Note that we have
|
||||||
|
to pass a deep copy of `ui.sort`. If `ui.sort` and the lists `sort` option
|
||||||
|
were references to the same array, then changing `ui.sort` and passing it
|
||||||
|
as `sort` option would no longer register as a change. In other words: to
|
||||||
|
update the options of a widget, don't hold references and update them, but
|
||||||
|
use the widget's `options` method.
|
||||||
|
*/
|
||||||
function order() {
|
function order() {
|
||||||
ui.sort[0].operator = ui.sort[0].operator == '+' ? '-' : '+';
|
ui.sort[0].operator = ui.sort[0].operator == '+' ? '-' : '+';
|
||||||
$order.options(getOptions());
|
$order.options(getOptions());
|
||||||
$list.options({sort: Ox.clone(ui.sort, true)});
|
$list.options({sort: Ox.clone(ui.sort, true)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This renders the selected item. In grid view, we display all the country's
|
||||||
|
properties, in list view, we show a flag icon.
|
||||||
|
*/
|
||||||
function renderItem() {
|
function renderItem() {
|
||||||
var code = ui.selected[0];
|
var code = ui.selected[0];
|
||||||
$item.empty();
|
$item.empty();
|
||||||
|
@ -281,6 +417,9 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
...
|
||||||
|
*/
|
||||||
function renderList() {
|
function renderList() {
|
||||||
return ui.view == 'grid'
|
return ui.view == 'grid'
|
||||||
? Ox.IconList({
|
? Ox.IconList({
|
||||||
|
@ -336,6 +475,9 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A handler for the `select` event of the list.
|
||||||
|
*/
|
||||||
function select(data) {
|
function select(data) {
|
||||||
var id = data.ids[0];
|
var id = data.ids[0];
|
||||||
if (id) {
|
if (id) {
|
||||||
|
@ -351,12 +493,17 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
renderItem();
|
renderItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A handler for both the `sort` event of the table and the `change` event of
|
||||||
|
the sort select element. In the latter case, we patch the event's properties
|
||||||
|
to match the signature of the former.
|
||||||
|
*/
|
||||||
function sort(data) {
|
function sort(data) {
|
||||||
if (data.value) {
|
if (data.value) {
|
||||||
data = {
|
data = {
|
||||||
key: data.value,
|
key: data.value,
|
||||||
operator: Ox.getObjectById(columns, data.value).operator
|
operator: Ox.getObjectById(columns, data.value).operator
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
ui.sort = [{key: data.key, operator: data.operator}];
|
ui.sort = [{key: data.key, operator: data.operator}];
|
||||||
$sort.options({value: data.key});
|
$sort.options({value: data.key});
|
||||||
|
@ -364,6 +511,9 @@ Ox.load(['Geo', 'UI'], function() {
|
||||||
$list.options({sort: Ox.clone(ui.sort, true)});
|
$list.options({sort: Ox.clone(ui.sort, true)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
And a handler for the change event of the `view` switch.
|
||||||
|
*/
|
||||||
function view(data) {
|
function view(data) {
|
||||||
ui.view = data.value;
|
ui.view = data.value;
|
||||||
$sort[ui.view == 'grid' ? 'show' : 'hide']();
|
$sort[ui.view == 'grid' ? 'show' : 'hide']();
|
||||||
|
|
Loading…
Reference in a new issue