add docco-style Ox.SourceViewer, Ox.ExamplePage and Ox.ExamplePanel, and a demo
This commit is contained in:
parent
7b7bedb65a
commit
ef0e161ab0
16 changed files with 224002 additions and 3 deletions
31
demos/examplepanel/index.html
Normal file
31
demos/examplepanel/index.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OxJS ExamplePanel Demo</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<script type="text/javascript" src="../../dev/Ox.js"></script>
|
||||||
|
<script>
|
||||||
|
Ox.load('UI', function() {
|
||||||
|
///*
|
||||||
|
Ox.ExamplePanel({
|
||||||
|
examples: ['cities'],
|
||||||
|
path: Ox.PATH + '../examples/',
|
||||||
|
replace: [[/\b(Ox[\.\w]+)\b/g, '<b>$1</b>']]
|
||||||
|
})
|
||||||
|
.appendTo(Ox.$body);
|
||||||
|
//*/
|
||||||
|
/*
|
||||||
|
Ox.ExamplePage({
|
||||||
|
height: window.innerHeight,
|
||||||
|
html: Ox.PATH + '../examples/cities/index.html',
|
||||||
|
js: Ox.PATH + '../examples/cities/js/example.js',
|
||||||
|
title: 'Cities',
|
||||||
|
width: window.innerWidth
|
||||||
|
})
|
||||||
|
.appendTo(Ox.$body);
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
41
examples/cities/css/example.css
Normal file
41
examples/cities/css/example.css
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#toolbar > .OxElement:first-child {
|
||||||
|
float: left;
|
||||||
|
margin: 4px 2px 4px 4px;
|
||||||
|
}
|
||||||
|
#toolbar > .OxElement:last-child {
|
||||||
|
float: right;
|
||||||
|
margin: 4px 4px 4px 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OxDialog #content {
|
||||||
|
padding: 8px 16px 8px 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.OxDialog img {
|
||||||
|
float: left;
|
||||||
|
width: 256px;
|
||||||
|
height: 256px;
|
||||||
|
border-radius: 16px;
|
||||||
|
margin: 8px;
|
||||||
|
//background: rgb(128, 128, 128);
|
||||||
|
box-shadow: 0 0 1px rgb(128, 128, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
.OxTextList .OxItem .OxCell > div.region {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
.OxTextList .OxItem .OxCell > img.flag {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
margin: 0 0 0 -3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
.OxTextList .OxItem .OxCell > img.capital {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin: 2px 0 0 -1px;
|
||||||
|
}
|
14
examples/cities/index.html
Normal file
14
examples/cities/index.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Cities</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<meta name="keywords" content="Ox.Map, Ox.TextList"/>
|
||||||
|
<link rel="shortcut icon" type="image/png" href="../../source/Ox/png/OxJS16.png"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/example.css"/>
|
||||||
|
<script type="text/javascript" src="../../dev/Ox.js"></script>
|
||||||
|
<script type="text/javascript" src="js/example.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
509
examples/cities/js/example.js
Normal file
509
examples/cities/js/example.js
Normal file
|
@ -0,0 +1,509 @@
|
||||||
|
/*
|
||||||
|
...
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/*
|
||||||
|
Since we will be doing some mapping, we have to load the Geo module.
|
||||||
|
*/
|
||||||
|
Ox.load({UI: {}, Geo: {}}, function() {
|
||||||
|
|
||||||
|
Ox.getJSON('json/cities.json', function(cities) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
The JSON data originally comes from geonames.org. It's an array of
|
||||||
|
10,000 city objects, each of which has the following properties:
|
||||||
|
<pre>
|
||||||
|
{
|
||||||
|
"country_code": "CN",
|
||||||
|
"elevation": 0,
|
||||||
|
"feature_code": "PPLA",
|
||||||
|
"latitude": 31.22222,
|
||||||
|
"longitude": 121.45806,
|
||||||
|
"name": "Shanghai",
|
||||||
|
"population": 14608512
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
*/
|
||||||
|
cities = cities.map(function(data, id) {
|
||||||
|
/*
|
||||||
|
First of all, we have to patch this data, so that it becomes more useful
|
||||||
|
both for the list and the map. Ox.getCountryByCode gives us the names of
|
||||||
|
the country, region and continent. For the map, we need a geoname, and
|
||||||
|
the cities have to be rectangular areas, not just points. So we set the
|
||||||
|
area to 100 square meters per inhabitant, which will turn out to be
|
||||||
|
relatively realistic. Then we calculate how large the resulting square
|
||||||
|
will be, in degrees. (The number of degrees from west to east depends on
|
||||||
|
the city's proximity to the equator. OxJS has some utility functions
|
||||||
|
built in that make this easy to compute.) Finally, we can set the values
|
||||||
|
for south, north, west and east. A nice side effect of deriving the size
|
||||||
|
of the city from its population is that the map, which will always show
|
||||||
|
the largest places in the visible area, will now show the most populated
|
||||||
|
cities.
|
||||||
|
*/
|
||||||
|
var area = Math.max(data.population, 1) * 100,
|
||||||
|
country = Ox.getCountryByCode(data.country_code),
|
||||||
|
latSize = Math.sqrt(area) / Ox.EARTH_CIRCUMFERENCE * 360,
|
||||||
|
lngSize = Math.sqrt(area) * Ox.getDegreesPerMeter(data.latitude);
|
||||||
|
/*
|
||||||
|
Our city object will look like this:<pre>
|
||||||
|
{
|
||||||
|
"area": 1460851200,
|
||||||
|
"capital": false,
|
||||||
|
"country": "China",
|
||||||
|
"east": 121.65880869475835,
|
||||||
|
"elevation": 0,
|
||||||
|
"geoname": "Shanghai, China",
|
||||||
|
"id": "0",
|
||||||
|
"lat": 31.22222,
|
||||||
|
"lng": 121.45806,
|
||||||
|
"name": "Shanghai",
|
||||||
|
"north": 31.393892916013158,
|
||||||
|
"population": 14608512,
|
||||||
|
"region": "Asia, Eastern Asia, China",
|
||||||
|
"south": 31.050547083986842,
|
||||||
|
"west": 121.25731130524166
|
||||||
|
}</pre>
|
||||||
|
Obviously, in a real-world scenario, you would make sure that the
|
||||||
|
data already comes in this form.
|
||||||
|
*/
|
||||||
|
return {
|
||||||
|
area: area,
|
||||||
|
capital: data.feature_code == 'PPLC',
|
||||||
|
country: country.name,
|
||||||
|
east: data.longitude + lngSize / 2,
|
||||||
|
elevation: data.elevation,
|
||||||
|
geoname: [data.name, country.name].join(', '),
|
||||||
|
id: id.toString(),
|
||||||
|
lat: data.latitude,
|
||||||
|
lng: data.longitude,
|
||||||
|
name: data.name,
|
||||||
|
north: data.latitude + latSize / 2,
|
||||||
|
population: data.population,
|
||||||
|
region: [country.continent, country.region, country.name].join(', '),
|
||||||
|
south: data.latitude - latSize / 2,
|
||||||
|
west: data.longitude - lngSize / 2
|
||||||
|
};
|
||||||
|
/**/
|
||||||
|
});
|
||||||
|
|
||||||
|
var listAPI = Ox.api(cities, {
|
||||||
|
cache: true,
|
||||||
|
sort: ['-population', '+name'],
|
||||||
|
sums: ['population']
|
||||||
|
}),
|
||||||
|
$preview = Ox.Button({
|
||||||
|
disabled: true,
|
||||||
|
selectable: true,
|
||||||
|
title: 'view',
|
||||||
|
type: 'image'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
change: function(data) {
|
||||||
|
$list[(data.value ? 'open' : 'close') + 'Preview']();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
/*
|
||||||
|
As we want the list to be searchable, we add an input element.
|
||||||
|
*/
|
||||||
|
$find = Ox.Input({
|
||||||
|
clear: true,
|
||||||
|
placeholder: 'Find',
|
||||||
|
width: 192
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
submit: function(data) {
|
||||||
|
listAPI({
|
||||||
|
keys: [],
|
||||||
|
query: {
|
||||||
|
conditions: data.value ? [
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
operator: '=',
|
||||||
|
value: data.value
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'region',
|
||||||
|
operator: '=',
|
||||||
|
value: data.value
|
||||||
|
}
|
||||||
|
] : [],
|
||||||
|
operator: '|'
|
||||||
|
}
|
||||||
|
}, function(result) {
|
||||||
|
$list.options({items: result.data.items});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$toolbar = Ox.Bar({size: 24})
|
||||||
|
.attr({id: 'toolbar'})
|
||||||
|
.append($preview)
|
||||||
|
.append($find),
|
||||||
|
$list = Ox.TextList({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We don't want to display the id, so we omit the
|
||||||
|
visible attribute, which defaults to false. We still
|
||||||
|
have to include the id here, since is the unique key
|
||||||
|
of our table. In consequence, whenever the list
|
||||||
|
fires a select event, it will reference this value
|
||||||
|
as the item's id.
|
||||||
|
*/
|
||||||
|
id: 'id',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Id',
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We use the format function to display the region as
|
||||||
|
a colored icon with a tooltip. The OxTypeIcon class
|
||||||
|
makes the icon themed (its border color will depend
|
||||||
|
on the current theme), the region class is added to
|
||||||
|
apply our own custom CSS, and Ox.getGeoColor returns
|
||||||
|
a color for the region. Note that the actual value
|
||||||
|
is 'Continent, Region, Country', which results in a
|
||||||
|
nicer sort order than just 'Region'.
|
||||||
|
*/
|
||||||
|
format: function(value) {
|
||||||
|
var region = value.split(', ')[1];
|
||||||
|
return Ox.Element({
|
||||||
|
tooltip: region
|
||||||
|
})
|
||||||
|
.addClass('OxTypeIcon region')
|
||||||
|
.css({
|
||||||
|
background: 'rgb('
|
||||||
|
+ Ox.getGeoColor(region).join(', ')
|
||||||
|
+ ')'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
id: 'region',
|
||||||
|
/*
|
||||||
|
The operator indicates that we want the default sort
|
||||||
|
order for this column to be ascending.
|
||||||
|
*/
|
||||||
|
operator: '+',
|
||||||
|
/*
|
||||||
|
We want the column title to be a symbol, so we pass
|
||||||
|
the 'icon' symbol at a titleImage. We can pick
|
||||||
|
anything from the collection of symbols that comes
|
||||||
|
with Ox.UI. The column still needs a textual title,
|
||||||
|
to be displayed in the menu that allows to show or
|
||||||
|
hide specific columns.
|
||||||
|
*/
|
||||||
|
title: 'Region',
|
||||||
|
titleImage: 'icon',
|
||||||
|
/**/
|
||||||
|
visible: true,
|
||||||
|
width: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Ox.getFlagByGeoname and Ox.getFlagByCountryCode
|
||||||
|
return pretty flag icons.
|
||||||
|
*/
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.Element({
|
||||||
|
element: '<img>',
|
||||||
|
tooltip: value
|
||||||
|
})
|
||||||
|
.addClass('flag')
|
||||||
|
.attr({
|
||||||
|
src: Ox.getFlagByGeoname(value)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
id: 'country',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Country',
|
||||||
|
titleImage: 'flag',
|
||||||
|
visible: true,
|
||||||
|
width: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return value
|
||||||
|
? $('<img>')
|
||||||
|
.addClass('capital')
|
||||||
|
.attr({
|
||||||
|
src: Ox.UI.getImageURL('symbolStar')
|
||||||
|
})
|
||||||
|
: '';
|
||||||
|
},
|
||||||
|
id: 'capital',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Capital',
|
||||||
|
titleImage: 'star',
|
||||||
|
visible: true,
|
||||||
|
width: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The format function has a second argument that
|
||||||
|
contains the values of all columns. This allows us
|
||||||
|
to format a value dependent on other values. In this
|
||||||
|
case, we want to display the name in bold if the
|
||||||
|
value for capital is true.
|
||||||
|
*/
|
||||||
|
format: function(value, data) {
|
||||||
|
return data.capital
|
||||||
|
? '<b>' + value + '</b>'
|
||||||
|
: value;
|
||||||
|
},
|
||||||
|
id: 'name',
|
||||||
|
operator: '+',
|
||||||
|
/*
|
||||||
|
As it wouldn't make much sense to display the list
|
||||||
|
without the name column, we make it non-removable.
|
||||||
|
*/
|
||||||
|
removable: false,
|
||||||
|
title: 'Name',
|
||||||
|
visible: true,
|
||||||
|
width: 128
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Since the following values are numbers, they should
|
||||||
|
be right-aligned. Also, we use some of the built-in
|
||||||
|
format functions.
|
||||||
|
*/
|
||||||
|
align: 'right',
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.formatNumber(value);
|
||||||
|
},
|
||||||
|
id: 'population',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Population',
|
||||||
|
visible: true,
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.formatDegrees(value, 'lat');
|
||||||
|
},
|
||||||
|
align: 'right',
|
||||||
|
id: 'lat',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Latitude',
|
||||||
|
visible: true,
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.formatDegrees(value, 'lng');
|
||||||
|
},
|
||||||
|
align: 'right',
|
||||||
|
id: 'lng',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Longitude',
|
||||||
|
visible: true,
|
||||||
|
width: 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.formatNumber(value) + ' m';
|
||||||
|
},
|
||||||
|
align: 'right',
|
||||||
|
id: 'elevation',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Elevation',
|
||||||
|
width: 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
This allows the user to move the columns around
|
||||||
|
*/
|
||||||
|
columnsMovable: true,
|
||||||
|
/*
|
||||||
|
This enables the UI to show or hide specific columns
|
||||||
|
*/
|
||||||
|
columnsRemovable: true,
|
||||||
|
/*
|
||||||
|
This makes sure the column titles get displayed
|
||||||
|
*/
|
||||||
|
columnsVisible: true,
|
||||||
|
items: cities,
|
||||||
|
/*
|
||||||
|
FIXME: Actually, 'keys' doesn't make so much sense when the
|
||||||
|
API is local, since the list has been passed all data anyway
|
||||||
|
*/
|
||||||
|
keys: ['capital'],
|
||||||
|
max: 1,
|
||||||
|
scrollbarVisible: true,
|
||||||
|
/*
|
||||||
|
We have to specify the default sort order.
|
||||||
|
*/
|
||||||
|
sort: ['-population', '+name'],
|
||||||
|
sums: ['population']
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
closepreview: function() {
|
||||||
|
$preview.options({value: false});
|
||||||
|
$dialog.close();
|
||||||
|
},
|
||||||
|
init: function(data) {
|
||||||
|
$status.html(
|
||||||
|
(data.items ? Ox.formatNumber(data.items) : 'No')
|
||||||
|
+ ' Cit' + (data.items == 1 ? 'y' : 'ies')
|
||||||
|
+ ', Populaion: ' + (
|
||||||
|
data.population
|
||||||
|
? Ox.formatNumber(data.population)
|
||||||
|
: 'None'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
open: function(data) {
|
||||||
|
$map.zoomToPlace();
|
||||||
|
},
|
||||||
|
openpreview: function(data) {
|
||||||
|
var item = Ox.getObjectById(cities, data.ids[0]);
|
||||||
|
$flagImage = $('<img>')
|
||||||
|
.attr({
|
||||||
|
src: Ox.getFlagByGeoname(item.country, 256)
|
||||||
|
});
|
||||||
|
$mapImage = Ox.MapImage({
|
||||||
|
height: 256,
|
||||||
|
markers: [item],
|
||||||
|
place: Ox.getCountryByGeoname(item.country),
|
||||||
|
width: 256
|
||||||
|
});
|
||||||
|
setImageSizes();
|
||||||
|
$preview.options({value: true});
|
||||||
|
$dialog.options({
|
||||||
|
content: $content = Ox.Element()
|
||||||
|
.attr({id: 'content'})
|
||||||
|
.append($flagImage)
|
||||||
|
.append($mapImage),
|
||||||
|
title: [item.name, item.country].join(', ')
|
||||||
|
}).open();
|
||||||
|
},
|
||||||
|
select: function(data) {
|
||||||
|
$preview.options({disabled: data.ids.length == 0});
|
||||||
|
$map.options({selected: data.ids[0]}).panToPlace();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$flagImage,
|
||||||
|
$mapImage,
|
||||||
|
$content = Ox.Element(),
|
||||||
|
$dialog = Ox.Dialog({
|
||||||
|
closeButton: true,
|
||||||
|
content: $content,
|
||||||
|
fixedRatio: true,
|
||||||
|
focus: false,
|
||||||
|
height: 288,
|
||||||
|
maximizeButton: true,
|
||||||
|
maxHeight: 432,
|
||||||
|
maxWidth: 864,
|
||||||
|
minHeight: 144,
|
||||||
|
minWidth: 384,
|
||||||
|
width: 576
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
close: function() {
|
||||||
|
$list.closePreview();
|
||||||
|
},
|
||||||
|
resize: function(data) {
|
||||||
|
$content.css({height: data.height - 16 + 'px'})
|
||||||
|
setImageSizes();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$status = $('<div>').css({
|
||||||
|
margin: '3px',
|
||||||
|
fontSize: '9px',
|
||||||
|
textAlign: 'center'
|
||||||
|
}),
|
||||||
|
$statusbar = Ox.Bar({size: 16}).append($status),
|
||||||
|
$map = Ox.Map({
|
||||||
|
clickable: true,
|
||||||
|
keys: ['population'],
|
||||||
|
markerColor: function(place) {
|
||||||
|
return place.population === void 0 ? [128, 128, 128]
|
||||||
|
: place.population > 10000000 ? [255, 0, 0]
|
||||||
|
: place.population > 5000000 ? [255, 32, 0]
|
||||||
|
: place.population > 2000000 ? [255, 64, 0]
|
||||||
|
: place.population > 1000000 ? [255, 96, 0]
|
||||||
|
: place.population > 500000 ? [255, 128, 0]
|
||||||
|
: place.population > 200000 ? [255, 160, 0]
|
||||||
|
: place.population > 100000 ? [255, 192, 0]
|
||||||
|
: place.population > 50000 ? [255, 224, 0]
|
||||||
|
: [255, 255, 0];
|
||||||
|
},
|
||||||
|
markerSize: function(place) {
|
||||||
|
return place.population === void 0 ? 16
|
||||||
|
: place.population > 10000000 ? 24
|
||||||
|
: place.population > 5000000 ? 22
|
||||||
|
: place.population > 2000000 ? 20
|
||||||
|
: place.population > 1000000 ? 18
|
||||||
|
: place.population > 500000 ? 16
|
||||||
|
: place.population > 200000 ? 14
|
||||||
|
: place.population > 100000 ? 12
|
||||||
|
: place.population > 50000 ? 10
|
||||||
|
: 8;
|
||||||
|
},
|
||||||
|
places: cities,
|
||||||
|
showControls: true,
|
||||||
|
showToolbar: true,
|
||||||
|
showZoombar: true
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
select: function(data) {
|
||||||
|
$list.options({
|
||||||
|
selected: data.place ? [data.place.id] : []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
$listPanel = Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{element: $toolbar, size: 24},
|
||||||
|
{element: $list},
|
||||||
|
{element: $statusbar, size: 16}
|
||||||
|
],
|
||||||
|
orientation: 'vertical'
|
||||||
|
}),
|
||||||
|
$mainPanel = Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
element: $listPanel.bindEvent({
|
||||||
|
resize: function(data) {
|
||||||
|
$find.options({
|
||||||
|
width: data.size < 220
|
||||||
|
? data.size - 28
|
||||||
|
: 192
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
resizable: true,
|
||||||
|
resize: [176, 256, 336, 416, 496].map(function(size) {
|
||||||
|
return size + Ox.UI.SCROLLBAR_SIZE;
|
||||||
|
}),
|
||||||
|
size: 416 + Ox.UI.SCROLLBAR_SIZE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: $map.bindEvent({
|
||||||
|
resizeend: function(data) {
|
||||||
|
$map.resizeMap();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
],
|
||||||
|
orientation: 'horizontal'
|
||||||
|
})
|
||||||
|
.appendTo(Ox.$body);
|
||||||
|
|
||||||
|
function setImageSizes() {
|
||||||
|
var size = Math.floor(($dialog.options('width') - 64) / 2);
|
||||||
|
[$flagImage, $mapImage].forEach(function($image) {
|
||||||
|
$image.css({width: size + 'px', height: size + 'px'});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ox.$window.bind({
|
||||||
|
resize: function() {
|
||||||
|
$map.resizeMap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
100002
examples/cities/json/cities.json
Normal file
100002
examples/cities/json/cities.json
Normal file
File diff suppressed because it is too large
Load diff
74
examples/cities/py/txt2json.py
Normal file
74
examples/cities/py/txt2json.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import re
|
||||||
|
from ox.geo import get_country
|
||||||
|
|
||||||
|
def read_table(source, target, keys, filter_=lambda x: True, map_=lambda x: x, sort_=lambda x: x):
|
||||||
|
def parse_value(str, t):
|
||||||
|
if type(t) == float:
|
||||||
|
str = float(str) if str else t
|
||||||
|
elif type(t) == int:
|
||||||
|
str = int(str) if str else t
|
||||||
|
return str
|
||||||
|
data = []
|
||||||
|
f = open(source)
|
||||||
|
for r, row in enumerate(f):
|
||||||
|
if row and row[0] != '#':
|
||||||
|
item = {}
|
||||||
|
cols = row[:-1].split('\t')
|
||||||
|
for c, col in enumerate(cols):
|
||||||
|
key = keys[c]
|
||||||
|
if type(key['type']) == list:
|
||||||
|
if col:
|
||||||
|
col = col.split(',')
|
||||||
|
value = map(lambda x: parse_value(x, key['type'][0]), col)
|
||||||
|
else:
|
||||||
|
value = []
|
||||||
|
else:
|
||||||
|
value = parse_value(col, key['type'])
|
||||||
|
item[key['name']] = value
|
||||||
|
if filter_(item):
|
||||||
|
data.append(map_(item))
|
||||||
|
data = sorted(data, key=sort_)
|
||||||
|
f = open(target, 'w')
|
||||||
|
f.write(json.dumps(data, indent=4, sort_keys=True))
|
||||||
|
f.close()
|
||||||
|
print len(data), 'cities'
|
||||||
|
|
||||||
|
# http://download.geonames.org/export/dump/
|
||||||
|
# http://www.geonames.org/export/codes.html
|
||||||
|
source = '../txt/cities1000.txt'
|
||||||
|
target = '../json/cities.json'
|
||||||
|
keys = [
|
||||||
|
{'name': 'geonameid', 'type': 0},
|
||||||
|
{'name': 'name', 'type': ''},
|
||||||
|
{'name': 'asciiname', 'type': ''},
|
||||||
|
{'name': 'alternatenames', 'type': ['']},
|
||||||
|
{'name': 'latitude', 'type': 0.0},
|
||||||
|
{'name': 'longitude', 'type': 0.0},
|
||||||
|
{'name': 'feature_class', 'type': ''},
|
||||||
|
{'name': 'feature_code', 'type': ''},
|
||||||
|
{'name': 'country_code', 'type': ''},
|
||||||
|
{'name': 'cc2', 'type': ['']},
|
||||||
|
{'name': 'admin1_code', 'type': ''},
|
||||||
|
{'name': 'admin2_code', 'type': ''},
|
||||||
|
{'name': 'admin3_code', 'type': ''},
|
||||||
|
{'name': 'admin4_code', 'type': ''},
|
||||||
|
{'name': 'population', 'type': 0},
|
||||||
|
{'name': 'elevation', 'type': 0},
|
||||||
|
{'name': 'gtopo30', 'type': 0},
|
||||||
|
{'name': 'timezone', 'type': ''},
|
||||||
|
{'name': 'modification_date', 'type': ''}
|
||||||
|
]
|
||||||
|
filter_ = lambda x: re.search('^PPL(C|A)$', x['feature_code']) or x['population'] >= 49589
|
||||||
|
def map_(x):
|
||||||
|
data = {}
|
||||||
|
for key in [
|
||||||
|
'country_code', 'elevation', 'feature_code'
|
||||||
|
'latitude', 'longitude', 'name', 'population'
|
||||||
|
]:
|
||||||
|
data[key] = x[key]
|
||||||
|
return data
|
||||||
|
sort_ = lambda x: -x['population']
|
||||||
|
|
||||||
|
read_table(source, target, keys, filter_, map_, sort_)
|
122949
examples/cities/txt/cities1000.txt
Executable file
122949
examples/cities/txt/cities1000.txt
Executable file
File diff suppressed because it is too large
Load diff
|
@ -1899,6 +1899,35 @@ Scrollbars
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================================================================================
|
||||||
|
SourceViewer
|
||||||
|
================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
.OxSourceViewer table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.OxSourceViewer td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.OxSourceViewer .OxComment {
|
||||||
|
padding: 4px 8px 4px 8px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-right-style: solid;
|
||||||
|
font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console;
|
||||||
|
line-height: 16px;
|
||||||
|
//white-space: pre;
|
||||||
|
-moz-user-select: text;
|
||||||
|
-webkit-user-select: text;
|
||||||
|
}
|
||||||
|
.OxSourceViewer .OxComment pre {
|
||||||
|
font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console;
|
||||||
|
line-height: 16px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================================================================================
|
================================================================================
|
||||||
SyntaxHightlighter
|
SyntaxHightlighter
|
||||||
|
@ -1909,7 +1938,7 @@ SyntaxHightlighter
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console;
|
font-family: Menlo, Monaco, DejaVu Sans Mono, Bitstream Vera Sans Mono, Consolas, Lucida Console;
|
||||||
//line-height: 14px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
.OxSyntaxHighlighter > .OxLineNumbers {
|
.OxSyntaxHighlighter > .OxLineNumbers {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
|
@ -20,6 +20,8 @@ Ox.DocPanel <f> Documentation Panel
|
||||||
|
|
||||||
Ox.DocPanel = function(options, self) {
|
Ox.DocPanel = function(options, self) {
|
||||||
|
|
||||||
|
// FIXME: defaults should be falsy
|
||||||
|
|
||||||
self = self || {};
|
self = self || {};
|
||||||
var that = Ox.Element({}, self)
|
var that = Ox.Element({}, self)
|
||||||
.defaults({
|
.defaults({
|
||||||
|
@ -65,8 +67,8 @@ Ox.DocPanel = function(options, self) {
|
||||||
function loadList(callback) {
|
function loadList(callback) {
|
||||||
|
|
||||||
var counter = 0,
|
var counter = 0,
|
||||||
length = self.options.files.length,
|
docItems = [],
|
||||||
docItems = [];
|
length = self.options.files.length;
|
||||||
|
|
||||||
self.options.files.forEach(function(file) {
|
self.options.files.forEach(function(file) {
|
||||||
Ox.doc(self.options.path + file, function(fileItems) {
|
Ox.doc(self.options.path + file, function(fileItems) {
|
137
source/Ox.UI/js/Code/Ox.ExamplePage.js
Normal file
137
source/Ox.UI/js/Code/Ox.ExamplePage.js
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
Ox.ExamplePage = function(options, self) {
|
||||||
|
|
||||||
|
self = self || {};
|
||||||
|
var that = Ox.Element({}, self)
|
||||||
|
.defaults({
|
||||||
|
html: '',
|
||||||
|
js: '',
|
||||||
|
replace: [],
|
||||||
|
selected: 'source',
|
||||||
|
title: ''
|
||||||
|
})
|
||||||
|
.options(options || {});
|
||||||
|
|
||||||
|
self.$toolbar = Ox.Bar({size: 24});
|
||||||
|
|
||||||
|
self.$title = Ox.Label({
|
||||||
|
title: self.options.title
|
||||||
|
})
|
||||||
|
.css({float: 'left', margin: '4px'})
|
||||||
|
.appendTo(self.$toolbar)
|
||||||
|
|
||||||
|
self.$reloadButton = Ox.Button({
|
||||||
|
disabled: self.options.selected == 'source',
|
||||||
|
title: 'redo',
|
||||||
|
tooltip: 'Reload',
|
||||||
|
type: 'image'
|
||||||
|
})
|
||||||
|
.css({float: 'right', margin: '4px 4px 4px 2px'})
|
||||||
|
.bindEvent({
|
||||||
|
click: function() {
|
||||||
|
self.$frame.attr({src: self.options.html});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.appendTo(self.$toolbar);
|
||||||
|
|
||||||
|
self.$tabs = Ox.ButtonGroup({
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
id: 'source',
|
||||||
|
title: 'View Source'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'live',
|
||||||
|
title: 'View Live'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
selectable: true,
|
||||||
|
value: self.options.selected
|
||||||
|
})
|
||||||
|
.css({float: 'right', margin: '4px 2px 4px 4px'})
|
||||||
|
.bindEvent({
|
||||||
|
change: function(data) {
|
||||||
|
self.options.selected = data.value;
|
||||||
|
self.$reloadButton.options({disabled: data.value == 'source'});
|
||||||
|
self.$content.animate({
|
||||||
|
marginLeft: data.value == 'source'
|
||||||
|
? 0 : -self.options.width + 'px'
|
||||||
|
}, 250, function() {
|
||||||
|
if (data.value == 'live' && !self.$frame.attr('src')) {
|
||||||
|
self.$frame.attr({src: self.options.html});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.appendTo(self.$toolbar);
|
||||||
|
|
||||||
|
self.$viewer = Ox.SourceViewer({
|
||||||
|
file: self.options.js,
|
||||||
|
replace: self.options.replace
|
||||||
|
})
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: self.options.width + 'px',
|
||||||
|
height: self.options.height - 24 + 'px'
|
||||||
|
});
|
||||||
|
self.$frame = Ox.Element('<iframe>')
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
left: self.options.width + 'px',
|
||||||
|
top: 0,
|
||||||
|
border: 0
|
||||||
|
})
|
||||||
|
.attr({
|
||||||
|
width: self.options.width,
|
||||||
|
height: self.options.height
|
||||||
|
});
|
||||||
|
self.$content = Ox.Element()
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
width: self.options.width * 2 + 'px'
|
||||||
|
})
|
||||||
|
.append(self.$viewer)
|
||||||
|
.append(self.$frame)
|
||||||
|
self.$container = Ox.Element()
|
||||||
|
.append(self.$content)
|
||||||
|
|
||||||
|
that.setElement(
|
||||||
|
Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{element: self.$toolbar, size: 24},
|
||||||
|
{element: self.$container}
|
||||||
|
],
|
||||||
|
orientation: 'vertical'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
Ox.$window.bind({
|
||||||
|
resize: function() {
|
||||||
|
setSize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(setSize, 100);
|
||||||
|
|
||||||
|
function setSize() {
|
||||||
|
self.options.width = that.width();
|
||||||
|
self.options.height = that.height();
|
||||||
|
self.$content.css({
|
||||||
|
width: self.options.width * 2 + 'px',
|
||||||
|
})
|
||||||
|
self.$viewer.css({
|
||||||
|
width: self.options.width + 'px',
|
||||||
|
height: self.options.height - 24 + 'px'
|
||||||
|
})
|
||||||
|
self.$frame.attr({
|
||||||
|
width: self.options.width,
|
||||||
|
height: self.options.height - 24
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return that;
|
||||||
|
|
||||||
|
};
|
108
source/Ox.UI/js/Code/Ox.ExamplePanel.js
Normal file
108
source/Ox.UI/js/Code/Ox.ExamplePanel.js
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Ox.ExamplePanel = function(options, self) {
|
||||||
|
|
||||||
|
self = self || {};
|
||||||
|
var that = Ox.Element({}, self)
|
||||||
|
.defaults({
|
||||||
|
collapsibe: false,
|
||||||
|
examples: [],
|
||||||
|
path: '',
|
||||||
|
replace: [],
|
||||||
|
resizable: false,
|
||||||
|
resize: [],
|
||||||
|
size: 256,
|
||||||
|
})
|
||||||
|
.options(options || {})
|
||||||
|
|
||||||
|
self.$list = Ox.Element();
|
||||||
|
self.$page = Ox.Element();
|
||||||
|
|
||||||
|
that.setElement(
|
||||||
|
self.$panel = Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
collapsible: self.options.collapsible,
|
||||||
|
element: self.$list,
|
||||||
|
resizable: self.options.resizable,
|
||||||
|
resize: self.options.resize,
|
||||||
|
size: self.options.size
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: self.$page
|
||||||
|
}
|
||||||
|
],
|
||||||
|
orientation: 'horizontal'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
loadList(function(items) {
|
||||||
|
self.items = items;
|
||||||
|
self.$list = Ox.TextList({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
id: 'id',
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'title',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Title',
|
||||||
|
visible: true,
|
||||||
|
width: self.options.size - Ox.UI.SCROLLBAR_SIZE
|
||||||
|
}
|
||||||
|
],
|
||||||
|
items: self.items,
|
||||||
|
scrollbarVisible: true,
|
||||||
|
sort: ['+title']
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
select: function(data) {
|
||||||
|
var item;
|
||||||
|
if (data.ids.length) {
|
||||||
|
item = Ox.getObjectById(self.items, data.ids[0]);
|
||||||
|
self.$panel.replaceElement(1,
|
||||||
|
self.$page = Ox.ExamplePage({
|
||||||
|
height: window.innerHeight,
|
||||||
|
html: item.html,
|
||||||
|
js: item.js,
|
||||||
|
replace: self.options.replace,
|
||||||
|
title: item.title,
|
||||||
|
width: window.innerWidth - self.options.size
|
||||||
|
})
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.$page.empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.$panel.replaceElement(0, self.$list);
|
||||||
|
that.triggerEvent('load', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadList(callback) {
|
||||||
|
var items = [];
|
||||||
|
self.options.examples.forEach(function(example) {
|
||||||
|
var file = self.options.path + example + '/index.html';
|
||||||
|
Ox.get(file, function(html) {
|
||||||
|
var keywords = html.match(/<meta name="keywords" content="(.+)"/),
|
||||||
|
title = html.match(/<title>(.+)<\/title>/);
|
||||||
|
items.push({
|
||||||
|
html: file,
|
||||||
|
id: example,
|
||||||
|
js: self.options.path + example + '/js/example.js',
|
||||||
|
keywords: keywords ? keywords[1].split(', ') : [],
|
||||||
|
title: title ? title[1] : 'Untitled'
|
||||||
|
});
|
||||||
|
items.length == self.options.examples.length && callback(items);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseExample() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return that;
|
||||||
|
|
||||||
|
};
|
77
source/Ox.UI/js/Code/Ox.SourceViewer.js
Normal file
77
source/Ox.UI/js/Code/Ox.SourceViewer.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Ox.SourceViewer = function(options, self) {
|
||||||
|
|
||||||
|
self = self || {};
|
||||||
|
var that = Ox.Container({}, self)
|
||||||
|
.defaults({
|
||||||
|
file: '',
|
||||||
|
replace: []
|
||||||
|
})
|
||||||
|
.options(options)
|
||||||
|
.addClass('OxSourceViewer');
|
||||||
|
|
||||||
|
self.replace = Ox.merge(
|
||||||
|
[[
|
||||||
|
// removes indentation inside <pre> tags
|
||||||
|
/<pre>([\s\S]+)<\/pre>/g,
|
||||||
|
function(pre, text) {
|
||||||
|
var lines = trim(text).split('\n'),
|
||||||
|
indent = Ox.min(lines.map(function(line) {
|
||||||
|
var match = line.match(/^\s+/);
|
||||||
|
return match ? match[0].length : 0;
|
||||||
|
}));
|
||||||
|
return '<pre>' + lines.map(function(line) {
|
||||||
|
return line.substr(indent);
|
||||||
|
}).join('\n') + '</pre>';
|
||||||
|
}
|
||||||
|
]],
|
||||||
|
self.options.replace
|
||||||
|
);
|
||||||
|
Ox.print('RE', self.replace)
|
||||||
|
|
||||||
|
self.$table = $('<table>').appendTo(that.$content);
|
||||||
|
|
||||||
|
Ox.get(self.options.file, function(source) {
|
||||||
|
var sections = [{comment: '', code: ''}];
|
||||||
|
Ox.tokenize(source).forEach(function(token, i) {
|
||||||
|
var text = source.substr(token.offset, token.length),
|
||||||
|
type = token.type == 'comment' ? 'comment' : 'code';
|
||||||
|
if (type == 'comment') {
|
||||||
|
i && sections.push({comment: '', code: ''});
|
||||||
|
text = /^\/\*/.test(text)
|
||||||
|
? Ox.sub(text, 2, -2)
|
||||||
|
: Ox.sub(text, 2);
|
||||||
|
self.replace.forEach(function(replace) {
|
||||||
|
text = text.replace(replace[0], replace[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ox.last(sections)[type] += text;
|
||||||
|
});
|
||||||
|
sections.forEach(function(section) {
|
||||||
|
var $section = $('<tr>'),
|
||||||
|
$comment = $('<td>')
|
||||||
|
.addClass('OxComment')
|
||||||
|
.html(trim(section.comment)),
|
||||||
|
$code = $('<td>')
|
||||||
|
.addClass('OxCode')
|
||||||
|
.append(
|
||||||
|
Ox.SyntaxHighlighter({
|
||||||
|
source: trim(section.code)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
$section
|
||||||
|
.append($comment)
|
||||||
|
.append($code)
|
||||||
|
.appendTo(self.$table);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function trim(str) {
|
||||||
|
// removes leading or trailing empty line
|
||||||
|
return str.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return that;
|
||||||
|
|
||||||
|
};
|
|
@ -642,6 +642,19 @@ Scrollbars
|
||||||
background: rgb(208, 208, 208);
|
background: rgb(208, 208, 208);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================================================================================
|
||||||
|
SourceViewer
|
||||||
|
================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
.OxThemeClassic .OxSourceViewer .OxComment {
|
||||||
|
border-color: rgb(208, 208, 208);
|
||||||
|
}
|
||||||
|
.OxThemeClassic .OxSourceViewer .OxCode {
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================================================================================
|
================================================================================
|
||||||
SyntaxHighlighter
|
SyntaxHighlighter
|
||||||
|
|
|
@ -628,6 +628,19 @@ Scrollbars
|
||||||
background: rgb(64, 64, 64);
|
background: rgb(64, 64, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================================================================================
|
||||||
|
SourceViewer
|
||||||
|
================================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
.OxThemeModern .OxSourceViewer .OxComment {
|
||||||
|
border-color: rgb(48, 48, 48);
|
||||||
|
}
|
||||||
|
.OxThemeModern .OxSourceViewer .OxCode {
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================================================================================
|
================================================================================
|
||||||
SyntaxHighlighter
|
SyntaxHighlighter
|
||||||
|
|
Loading…
Reference in a new issue