oxjs/source/Ox.UI/js/Map/MapEditor.js

1171 lines
40 KiB
JavaScript
Raw Normal View History

2011-11-05 16:46:53 +00:00
'use strict';
2011-05-16 08:24:46 +00:00
/*@
Ox.MapEditor <f> Map Editor
2011-05-16 08:24:46 +00:00
options <o> Options object
2011-10-03 16:14:01 +00:00
height <n|256> Height in px
labels <b|false> If true, show labels
mode <s|'add'> Mode ('add' or 'define')
2011-10-03 16:14:01 +00:00
places <a|f|null> Array of places, or function that returns places
selected <s|''> Id of the selected place
2011-10-03 16:14:01 +00:00
width <n|256> Width in px
self <o> Shared private variable
([options[, self]]) -> <o:Ox.SplitPanel> Map Editor
addplace <!> addplace
removeplace <!> removeplace
geocode <!> geocode
loadlist <!> loadlist
2011-05-16 08:24:46 +00:00
@*/
Ox.MapEditor = function(options, self) {
2011-04-22 22:03:10 +00:00
self = self || {};
var that = Ox.Element({}, self)
2011-10-03 16:14:01 +00:00
.defaults({
addPlace: null,
collapsible: false,
2012-02-20 18:31:45 +00:00
editPlace: null,
2011-10-30 14:40:33 +00:00
getMatches: null,
2012-02-20 18:31:45 +00:00
hasMatches: false,
2011-10-03 16:14:01 +00:00
height: 256,
labels: false,
mode: 'add',
2011-10-03 16:14:01 +00:00
pageLength: 100,
places: null,
removePlace: null,
2012-01-15 15:05:17 +00:00
selected: '',
2011-10-31 12:45:08 +00:00
showControls: false,
showLabels: false,
showTypes: false,
2011-10-03 16:14:01 +00:00
sort: [{key: 'geoname', operator: '+'}],
width: 256
})
.options(options || {})
2012-05-28 19:35:41 +00:00
.update({
height: function() {
self.$list.size();
self.$map.resizeMap();
},
selected: function() {
self.$list.options({selected: self.options.selected});
},
width: function() {
self.$map.resizeMap();
}
})
2011-10-03 16:14:01 +00:00
.css({
width: self.options.width + 'px',
height: self.options.height + 'px'
});
2011-04-22 22:03:10 +00:00
2011-05-29 10:42:38 +00:00
self.isAsync = Ox.isFunction(self.options.places);
// FIXME: duplicated, see MapMarker
self.typeColor = {
country: [64, 64, 255],
region: [0, 192, 192],
city: [255, 0, 0],
borough: [255, 128, 0],
street: [255, 255, 0],
building: [255, 64, 128],
feature: [0, 192, 0]
};
self.areaSize = {
2012-03-21 08:36:47 +00:00
1000000: 8, // 1 x 1 km
10000000000: 10 // 100 x 100 km
};
2011-04-22 22:03:10 +00:00
self.columns = [
{
2011-11-23 15:43:01 +00:00
format: function(value, data) {
2012-02-20 18:31:45 +00:00
return data.type
? $('<img>')
.attr({
src: Ox.getFlagByGeoname(data.geoname, 16)
})
.css({
width: '14px',
height: '14px',
borderRadius: '4px',
marginLeft: '-3px',
marginTop: 0
})
: '';
2011-04-22 22:03:10 +00:00
},
id: 'countryCode',
operator: '+',
resizable: false, // fixme: implement
sort: function(value) {
var names = value.split(', ');
if (!Ox.getCountryByGeoname(names[names.length - 1])) {
names.push('~');
}
return names.reverse().join(', ');
},
2013-05-09 13:03:33 +00:00
title: Ox._('Flag'),
titleImage: 'flag',
tooltip: function(data) {
return Ox.toTitleCase(data.geoname || '')
},
visible: true,
width: 16
},
{
format: function(value, data) {
var iconSize = 6;
Ox.forEach(self.areaSize, function(size, area) {
if (data.area >= area) {
iconSize = size;
} else {
2012-07-05 08:58:08 +00:00
return false; // break
}
});
return data.type
? $('<div>')
.addClass('OxTypeIcon')
.css({
width: iconSize + 'px',
height: iconSize + 'px',
borderRadius: (iconSize + 4) / 2 + 'px',
margin: [0, 0, 0, -3].map(function(v) {
return v + (10 - iconSize) / 2 + 'px';
}).join(' '),
background: 'rgb(' + self.typeColor[data.type].join(', ') + ')'
})
: '';
},
id: 'type',
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('Type'),
titleImage: 'icon',
tooltip: function(data) {
return Ox.toTitleCase(data.type || '');
},
2011-05-22 17:12:21 +00:00
visible: true,
width: 16
},
{
format: function(value, data) {
return data.type
? value
2012-02-20 18:31:45 +00:00
: $('<span>').addClass('OxWarning').html(value);
},
2011-05-22 17:12:21 +00:00
id: 'name',
operator: '+',
removable: false,
2013-05-09 13:03:33 +00:00
title: Ox._('Name'),
2011-05-22 17:12:21 +00:00
visible: true,
width: 144
},
2011-05-24 10:44:34 +00:00
{
format: function(value) {
return value.join('; ');
},
id: 'alternativeNames',
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('Alternative Names'),
2011-05-24 10:44:34 +00:00
visible: true,
width: 144
},
2011-05-22 17:12:21 +00:00
{
id: 'geoname',
operator: '+',
sort: function(value) {
2011-10-10 12:38:54 +00:00
var names = value.split(', ');
2011-05-28 08:46:39 +00:00
if (!Ox.getCountryByGeoname(names[names.length - 1])) {
names.push('~');
}
return names.reverse().join(', ');
},
2013-05-09 13:03:33 +00:00
title: Ox._('Geoname'),
visible: false,
width: 192
},
{
align: 'right',
format: toFixed,
id: 'lat',
2011-05-24 12:50:16 +00:00
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('Latitude'),
2011-04-22 22:03:10 +00:00
visible: true,
width: 64
2011-04-22 22:03:10 +00:00
},
{
align: 'right',
format: toFixed,
id: 'lng',
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('Longitude'),
visible: true,
width: 64
},
2011-04-22 22:03:10 +00:00
{
align: 'right',
format: toFixed,
2011-05-24 11:43:27 +00:00
id: 'south',
2011-04-22 22:03:10 +00:00
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('South'),
2011-05-24 11:43:27 +00:00
visible: false,
width: 64
2011-04-22 22:03:10 +00:00
},
{
align: 'right',
2011-05-24 11:43:27 +00:00
id: 'west',
2011-04-22 22:03:10 +00:00
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('West'),
2011-05-24 11:43:27 +00:00
visible: false,
width: 64
2011-04-22 22:03:10 +00:00
},
{
align: 'right',
format: toFixed,
2011-05-24 11:43:27 +00:00
id: 'north',
2011-04-22 22:03:10 +00:00
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('North'),
2011-04-22 22:03:10 +00:00
visible: false,
width: 64
2011-04-22 22:03:10 +00:00
},
{
align: 'right',
2011-05-24 11:43:27 +00:00
format: toFixed,
id: 'east',
2011-04-22 22:03:10 +00:00
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('East'),
2011-04-22 22:03:10 +00:00
visible: false,
width: 64
2011-04-22 22:03:10 +00:00
},
2011-05-24 11:43:27 +00:00
{
align: 'right',
2011-05-30 09:31:28 +00:00
format: {type: 'area', args: []},
2011-05-24 11:43:27 +00:00
id: 'area',
operator: '-',
2013-05-09 13:03:33 +00:00
title: Ox._('Area'),
2011-05-24 11:43:27 +00:00
visible: true,
width: 128
},
2011-04-22 22:03:10 +00:00
{
format: function(value) {
return Ox.encodeHTMLEntities(value);
},
2011-04-22 22:03:10 +00:00
id: 'user',
operator: '+',
2013-05-09 13:03:33 +00:00
title: Ox._('User'),
2011-04-22 22:03:10 +00:00
visible: false,
width: 96
},
{
2011-05-30 09:31:28 +00:00
format: function(value) {
return value.replace('T', ' ').replace('Z', '');
},
2011-04-22 22:03:10 +00:00
id: 'created',
operator: '-',
2013-05-09 13:03:33 +00:00
title: Ox._('Date Created'),
2011-04-22 22:03:10 +00:00
visible: false,
2012-05-26 15:48:19 +00:00
width: 128
2011-04-22 22:03:10 +00:00
},
{
2011-05-30 09:31:28 +00:00
format: function(value) {
return value.replace('T', ' ').replace('Z', '');
},
2011-04-22 22:03:10 +00:00
id: 'modified',
operator: '-',
2013-05-09 13:03:33 +00:00
title: Ox._('Date Modified'),
2011-04-22 22:03:10 +00:00
visible: false,
2012-05-26 15:48:19 +00:00
width: 128
2011-04-22 22:03:10 +00:00
}
];
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.columns.push({
align: 'right',
id: 'matches',
operator: '-',
2013-05-09 13:03:33 +00:00
title: Ox._('Matches'),
2012-02-20 18:31:45 +00:00
visible: true,
width: 64
});
2011-05-21 17:56:15 +00:00
self.$listToolbar = Ox.Bar({
2011-04-22 22:03:10 +00:00
size: 24
});
2011-05-21 17:56:15 +00:00
self.$findElement = Ox.FormElementGroup({
2011-04-22 22:03:10 +00:00
elements: [
2011-05-21 17:56:15 +00:00
self.$findSelect = Ox.Select({
2011-04-22 22:03:10 +00:00
items: [
2013-05-09 13:03:33 +00:00
{id: 'all', title: Ox._('Find: All')},
{id: 'name', title: Ox._('Find: Name')},
{id: 'alternativeNames', title: Ox._('Find: Alternative Names')},
{id: 'geoname', title: Ox._('Find: Geoname')}
2011-04-22 22:03:10 +00:00
],
overlap: 'right',
type: 'image'
})
.bindEvent({
change: function(data) {
2011-12-21 15:33:52 +00:00
var key = data.value,
value = self.$findInput.value();
value && updateList(key, value);
}
2011-04-22 22:03:10 +00:00
}),
2011-05-21 17:56:15 +00:00
self.$findInput = Ox.Input({
2011-04-22 22:03:10 +00:00
clear: true,
2013-07-17 10:19:57 +00:00
placeholder: Ox._('Find in List'),
2012-02-01 17:29:15 +00:00
width: 234
2011-04-22 22:03:10 +00:00
})
.bindEvent({
submit: function(data) {
var key = self.$findSelect.value(),
value = data.value;
updateList(key, value);
}
})
2011-04-22 22:03:10 +00:00
]
})
.css({float: 'right', margin: '4px'})
2011-06-01 08:39:33 +00:00
.appendTo(self.$listToolbar);
2011-04-22 22:03:10 +00:00
2012-06-27 07:41:10 +00:00
self.$list = Ox.TableList({
2011-04-22 22:03:10 +00:00
columns: self.columns,
columnsRemovable: true,
columnsVisible: true,
2012-02-20 18:31:45 +00:00
items: Ox.clone(self.options.places),
//items: self.options.places,
2012-02-05 01:56:23 +00:00
// area needed for icon, geoname needed for flag
keys: ['area', 'geoname', 'matches'],
2012-01-15 15:05:17 +00:00
max: 1,
min: 0,
2011-05-29 10:42:38 +00:00
pageLength: self.options.pageLength,
2011-04-22 22:03:10 +00:00
scrollbarVisible: true,
2012-01-15 15:05:17 +00:00
selected: self.options.selected ? [self.options.selected] : [],
sort: self.options.sort,
unique: 'id'
2011-04-22 22:03:10 +00:00
})
.bindEvent({
'delete': removeItem,
init: initList,
2011-05-24 14:51:40 +00:00
// fixme: do we need 0/shift-0? return already zooms to place
key_0: function() {
self.$map.panToPlace();
},
key_equal: function() {
self.$map.zoom(1);
},
key_minus: function() {
self.$map.zoom(-1);
},
key_shift_0: function() {
self.$map.zoomToPlace();
},
2011-04-22 22:03:10 +00:00
load: function() {
that.triggerEvent('loadlist');
},
open: openItem,
2012-06-30 15:01:43 +00:00
select: function(data) {
selectItem(data);
}
2011-04-22 22:03:10 +00:00
});
// if loaded with selection, set map and form
self.options.selected && self.$list.bindEventOnce({
load: function() {
self.$list.triggerEvent({
select: {ids: [self.options.selected]}
});
}
});
2011-05-21 17:56:15 +00:00
self.$listStatusbar = Ox.Bar({
size: 16
});
self.$status = Ox.Element()
.css({paddingTop: '2px', margin: 'auto', fontSize: '9px', textAlign: 'center'})
.appendTo(self.$listStatusbar);
2011-05-29 12:22:54 +00:00
self.$map = Ox.Map({
2012-02-20 18:31:45 +00:00
clickable: true,
editable: true,
2013-07-17 10:19:57 +00:00
findPlaceholder: Ox._('Find on Map'),
2012-02-20 18:31:45 +00:00
height: self.options.height,
places: self.options.places,
//statusbar: true,
showControls: self.options.showControls,
showLabels: self.options.showLabels,
showTypes: self.options.showTypes,
toolbar: true,
width: self.options.width - 514,//self.mapResize[1],
zoombar: true
})
.bindEvent({
/*
addplace: function(data) {
that.triggerEvent('addplace', data);
},
*/
changeplace: function(data) {
self.$placeForm.values(data).show();
self.$areaKmInput.value(Ox.formatArea(data.area));
},
changeplaceend: function(data) {
//Ox.Log('Map', 'ssP', self.selectedPlace);
var isResult = self.selectedPlace[0] == '_';
!isResult && editPlace([
'lat', 'lng', 'south', 'west', 'north', 'east', 'area'
]);
},
geocode: function(data) {
that.triggerEvent('geocode', data);
},
/*
resize: function() {
self.$map.resizeMap(); // fixme: don't need event
},
*/
2012-06-30 15:01:43 +00:00
select: selectPlace
2012-02-20 18:31:45 +00:00
});
2011-05-21 17:56:15 +00:00
2011-05-22 17:12:21 +00:00
self.$placeTitlebar = Ox.Bar({
2011-05-21 17:56:15 +00:00
size: 24
});
2011-05-24 06:15:44 +00:00
self.$placeTitle = $('<div>')
.hide()
.appendTo(self.$placeTitlebar);
if (self.options.mode == 'define') {
self.$findPlaceButton = Ox.Button({
title: 'find',
2013-05-09 13:03:33 +00:00
tooltip: Ox._('Find'),
type: 'image'
})
.css({float: 'left', margin: '4px'})
.bindEvent({
click: findPlace
})
.hide()
.appendTo(self.$placeTitle);
}
2011-10-09 21:13:16 +00:00
self.$placeFlag = $('<img>')
2011-05-22 17:12:21 +00:00
.addClass('OxFlag')
.attr({
2011-11-23 14:53:17 +00:00
src: Ox.getFlagByGeoname('', 16)
2011-05-22 17:12:21 +00:00
})
2011-05-29 19:05:31 +00:00
.css({float: 'left', margin: '4px'})
2011-05-24 06:15:44 +00:00
.appendTo(self.$placeTitle);
2011-10-09 21:13:16 +00:00
self.$placeName = Ox.Label({
2011-05-22 17:12:21 +00:00
title: '',
2011-05-29 19:05:31 +00:00
width: 208
})
.css({float: 'left', margin: '4px 0 4px 0'})
.bindEvent({
singleclick: function() {
self.$map.panToPlace();
},
doubleclick: function() {
self.$map.zoomToPlace();
}
})
.appendTo(self.$placeTitle);
2011-05-29 19:05:31 +00:00
self.$deselectPlaceButton = Ox.Button({
title: 'close',
2013-05-09 13:03:33 +00:00
tooltip: Ox._('Done'),
2011-05-29 19:05:31 +00:00
type: 'image'
2011-05-21 17:56:15 +00:00
})
.css({float: 'left', margin: '4px'})
2011-05-29 19:05:31 +00:00
.bindEvent({
click: function() {
2012-02-20 18:31:45 +00:00
self.$list.options({selected: []});
// FIXME: list doesn't fire select event
selectItem({ids: []});
2011-05-29 19:05:31 +00:00
}
})
2011-05-24 06:15:44 +00:00
.appendTo(self.$placeTitle);
2011-05-21 17:56:15 +00:00
2012-02-20 18:31:45 +00:00
self.$placeData = Ox.Element();
2012-02-20 18:31:45 +00:00
self.$placeForm = Ox.Form({
2012-05-24 07:45:33 +00:00
items: [].concat([
2012-02-20 18:31:45 +00:00
self.$nameInput = Ox.Input({
id: 'name',
2013-05-09 13:03:33 +00:00
label: Ox._('Name'),
labelWidth: 80,
2012-02-20 18:31:45 +00:00
width: 240
}),
self.$alternativeNamesInput = Ox.ArrayInput({
id: 'alternativeNames',
2013-05-09 13:03:33 +00:00
label: Ox._('Alternative Names'),
2012-02-20 18:31:45 +00:00
max: 10,
//sort: true,
values: [],
width: 240
}),
self.$geonameInput = Ox.Input({
id: 'geoname',
2013-05-09 13:03:33 +00:00
label: Ox._('Geoname'),
labelWidth: 80,
2012-02-20 18:31:45 +00:00
width: 240
}),
Ox.Input({
id: 'countryCode'
}).hide(),
Ox.Select({
id: 'type',
items: [
2013-05-09 13:03:33 +00:00
{id: 'country', title: Ox._('Country')},
{id: 'region', title: Ox._('Region')}, // administative (Kansas) or colloquial (Midwest)
{id: 'city', title: Ox._('City')},
{id: 'borough', title: Ox._('Borough')},
{id: 'street', title: Ox._('Street')}, // streets, squares, bridges, tunnels, ...
{id: 'building', title: Ox._('Building')}, // airports, stations, stadiums, military installations, ...
{id: 'feature', title: Ox._('Feature')} // continents, islands, rivers, lakes, seas, oceans, mountains...
2012-02-20 18:31:45 +00:00
],
2013-05-09 13:03:33 +00:00
label: Ox._('Type'),
labelWidth: 80,
2012-02-20 18:31:45 +00:00
width: 240
})
], ['Latitude', 'Longitude', 'South', 'West', 'North', 'East'].map(function(v) {
var id = (
v == 'Latitude' ? 'lat' : v == 'Longitude' ? 'lng' : v
).toLowerCase(),
max = ['Latitude', 'South', 'North'].indexOf(v) > -1 ? Ox.MAX_LATITUDE : 180;
return Ox.Input({
changeOnKeypress: true,
2012-02-20 18:31:45 +00:00
decimals: 8,
disabled: ['lat', 'lng'].indexOf(id) > -1,
id: id,
2013-05-09 13:03:33 +00:00
label: Ox._(v),
2012-02-20 18:31:45 +00:00
labelWidth: 80,
min: -max,
max: max,
type: 'float',
width: 240
});
}),
[
self.$areaInput = Ox.Input({
id: 'area',
type: 'float'
}).hide()
]),
2011-05-21 17:56:15 +00:00
width: 240
2011-06-01 09:11:22 +00:00
})
2012-02-20 18:31:45 +00:00
.css({margin: '8px'})
.hide()
2011-06-01 09:11:22 +00:00
.bindEvent({
2012-02-20 18:31:45 +00:00
change: function(data) {
2011-06-01 09:11:22 +00:00
var isResult = self.selectedPlace[0] == '_';
2012-02-20 18:31:45 +00:00
if (data.id == 'name') {
var name = data.data.value;
!isResult && self.$list.value(self.selectedPlace, 'name', name);
self.$placeName.options({title: name});
2012-02-20 18:31:45 +00:00
if (!self.isAsync) {
Ox.getObjectById(
self.options.places, self.selectedPlace
).name = name;
} else if (isResult) {
getMatches(this.values());
2012-02-20 18:31:45 +00:00
} else {
editPlace(['name']);
2012-02-20 18:31:45 +00:00
}
self.$map.value(self.selectedPlace, 'name', name);
2012-02-20 18:31:45 +00:00
} else if (data.id == 'alternativeNames') {
if (!self.isAsync) {
// ...
} else if (isResult) {
getMatches(this.values());
2012-02-20 18:31:45 +00:00
} else {
editPlace(['alternativeNames']);
2012-02-20 18:31:45 +00:00
}
self.$map.value(self.selectedPlace, 'alternativeNames', data.data.value);
} else if (data.id == 'geoname') {
var geoname = data.data.value,
country = Ox.getCountryByGeoname(geoname),
countryCode = country ? country.code : '';
self.$placeFlag.attr({
src: Ox.getFlagByGeoname(geoname, 16)
});
self.$placeForm.values({countryCode: countryCode});
if (!self.isAsync) {
if (!isResult) {
self.$list.value(self.selectedPlace, 'geoname', geoname);
self.$list.value(self.selectedPlace, 'countryCode', countryCode);
}
} else {
!isResult && editPlace(['countryCode', 'geoname']);
}
self.$map.value(self.selectedPlace, 'countryCode', countryCode);
self.$map.value(self.selectedPlace, 'geoname', geoname);
} else if (data.id == 'type') {
if (!self.isAsync) {
// ...
} else {
!isResult && editPlace(['type']);
2012-02-20 18:31:45 +00:00
}
self.$map.value(self.selectedPlace, 'type', data.data.value);
} else { // south, west, north, east
2012-02-20 18:31:45 +00:00
if (!self.isAsync) {
// ...
} else {
!isResult && editPlace([data.id]);
2012-02-20 18:31:45 +00:00
}
self.$map.value(self.selectedPlace, data.id, parseFloat(data.data.value));
}
2011-06-01 09:11:22 +00:00
}
2011-05-21 17:56:15 +00:00
})
2012-02-20 18:31:45 +00:00
.appendTo(self.$placeData);
2011-04-22 22:03:10 +00:00
2011-05-31 08:42:22 +00:00
self.$areaKmInput = Ox.Input({
disabled: true,
id: 'areaKm',
2013-05-09 13:03:33 +00:00
label: Ox._('Area'),
2011-05-31 08:42:22 +00:00
labelWidth: 80,
textAlign: 'right',
width: 240
})
2012-02-20 18:31:45 +00:00
.css({margin: '8px 8px 0 8px'})
.hide()
.appendTo(self.$placeData);
2011-05-31 08:42:22 +00:00
2012-02-20 18:31:45 +00:00
if (self.options.hasMatches) {
2011-10-30 14:40:33 +00:00
self.$matchesInput = Ox.Input({
2012-02-20 18:31:45 +00:00
disabled: true,
id: 'matches',
2013-05-09 13:03:33 +00:00
label: Ox._('Matches'),
2012-02-20 18:31:45 +00:00
labelWidth: 80,
type: 'int',
width: 240
})
.css({margin: '8px'})
.hide()
.appendTo(self.$placeData);
2011-10-30 14:40:33 +00:00
}
2011-05-21 17:56:15 +00:00
self.$placeStatusbar = Ox.Bar({
2011-10-03 16:37:05 +00:00
size: 24
});
2011-05-24 06:15:44 +00:00
self.$addPlaceButton = Ox.Button({
2013-05-09 13:03:33 +00:00
title: Ox._('Add Place'),
width: 90
2011-06-01 13:25:07 +00:00
})
.css({float: 'left', margin: '4px'})
2011-05-24 08:40:17 +00:00
.bindEvent({
click: function() {
2013-05-09 13:03:33 +00:00
if (this.options('title') == Ox._('Add Place')) {
addPlace();
2011-06-01 13:25:07 +00:00
} else {
removePlace();
2011-05-24 10:44:34 +00:00
}
2011-05-24 08:40:17 +00:00
}
})
2011-06-01 13:29:40 +00:00
.hide()
2011-05-24 06:15:44 +00:00
.appendTo(self.$placeStatusbar);
self.$newPlaceButton = Ox.Button({
2013-05-09 13:03:33 +00:00
title: Ox._('New Place'),
width: 70
})
.css({float: 'right', margin: '4px'})
.bindEvent({
click: function() {
self.$map.newPlace();
}
})
.appendTo(self.$placeStatusbar);
if (self.options.mode == 'define') {
self.$definePlaceButton = Ox.Button({
2013-05-09 13:03:33 +00:00
title: Ox._('Define Place'),
width: 80
})
.css({float: 'right', margin: '4px 0 4px 0'})
.bindEvent({
click: function() {
2013-05-09 13:03:33 +00:00
if (this.options('title') == Ox._('Define Place')) {
definePlace();
} else {
clearPlace();
}
}
})
.hide()
.appendTo(self.$placeStatusbar);
}
2011-05-21 17:56:15 +00:00
/*
2011-04-22 22:03:10 +00:00
self.mapResize = [
Math.round(self.options.width * 0.25),
Math.round(self.options.width * 0.5),
Math.round(self.options.width * 0.75)
];
2011-05-21 17:56:15 +00:00
*/
2011-04-22 22:03:10 +00:00
/*
2011-05-29 10:42:38 +00:00
if (!self.isAsync) {
2011-05-29 12:22:54 +00:00
self.placesLength = self.options.places.length;
setStatus();
2011-04-22 22:03:10 +00:00
} else {
self.options.places({}, function(results) {
self.placesLength = results.data.items;
2011-05-29 12:22:54 +00:00
setStatus();
2011-04-22 22:03:10 +00:00
});
}
*/
2011-04-22 22:03:10 +00:00
that.setElement(
Ox.SplitPanel({
2011-05-29 12:22:54 +00:00
elements: [
{
collapsible: self.options.collapsible,
2012-01-15 15:05:17 +00:00
element: self.$listPanel = Ox.SplitPanel({
2011-05-29 12:22:54 +00:00
elements: [
{
element: self.$listToolbar,
size: 24
},
{
element: self.$list
},
{
element: self.$listStatusbar,
size: 16
}
],
orientation: 'vertical'
}),
resizable: true,
resize: [256, 384, 512],
size: 256
},
2011-05-29 12:22:54 +00:00
{
element: self.$map
.bindEvent({
resize: function() {
self.$map.resizeMap();
}
2012-05-26 15:48:19 +00:00
})
2011-04-22 22:03:10 +00:00
},
2011-05-29 12:22:54 +00:00
{
collapsible: self.options.collapsible,
2011-05-29 12:22:54 +00:00
element: Ox.SplitPanel({
elements: [
{
element: self.$placeTitlebar,
size: 24
},
{
2012-02-20 18:31:45 +00:00
element: self.$placeData
2011-05-29 12:22:54 +00:00
},
{
element: self.$placeStatusbar,
size: 24
2011-05-22 12:39:57 +00:00
}
2011-05-29 12:22:54 +00:00
],
orientation: 'vertical'
})
.bindEvent({
resize: function(data) {
2011-10-09 21:13:16 +00:00
self.$placeName.options({width: data.size - 48});
2011-05-29 12:22:54 +00:00
// fixme: pass width through form
self.$placeFormItems.forEach(function($item) {
$item.options({width: data.size - 16});
2011-05-29 12:22:54 +00:00
});
self.$areaKmInput.options({width: data.size - 16});
self.$matchesInput && self.$matchesInput.options({width: data.size - 16});
2011-05-29 12:22:54 +00:00
}
}),
resizable: true,
resize: [256, 384],
2011-05-29 12:22:54 +00:00
size: 256
}
],
orientation: 'horizontal'
})
.addClass('OxMapEditor')
2011-05-29 12:22:54 +00:00
);
2011-04-22 22:03:10 +00:00
function addPlace() {
var place = self.$placeForm.values(),
country = Ox.getCountryByGeoname(place.geoname);
place.countryCode = country ? country.code : '';
if (!self.isAsync) {
2012-05-24 09:47:33 +00:00
place.id = self.selectedPlace.slice(1); // fixme: safe?
2011-05-29 17:44:48 +00:00
self.selectedPlace = place.id;
self.options.selected = place.id;
self.options.places.push(place);
self.$list.options({
items: Ox.clone(self.options.places)
}).options({
selected: [place.id]
});
2011-05-29 17:44:48 +00:00
self.$map.addPlace(place);
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({title: Ox._('Remove Place')});
//setStatus();
2012-02-20 18:31:45 +00:00
} else {
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({disabled: true, title: Ox._('Adding...')});
self.options.addPlace(encodeValues(place), function(result) {
if (result.status.code == 200) {
place.id = result.data.id;
self.options.selected = place.id;
self.selectedPlace = place.id;
self.$list.reloadList().options({selected: [place.id]});
self.$map.addPlace(place);
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.$matchesInput.value(
result.data.matches
).show();
self.options.mode == 'define' && self.$definePlaceButton.options({
disabled: !result.data.matches,
2013-05-09 13:03:33 +00:00
title: Ox._('Clear Place')
2012-02-20 18:31:45 +00:00
}).show();
self.$addPlaceButton.options({
disabled: false,
2013-05-09 13:03:33 +00:00
title: Ox._('Remove Place')
2012-02-20 18:31:45 +00:00
}).show();
} else if (result.status.code == 409) {
if (result.data.names.indexOf(self.$nameInput.value()) > -1) {
self.$nameInput.addClass('OxError');
}
2012-02-20 18:31:45 +00:00
self.$alternativeNamesInput.setErrors(result.data.names);
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({disabled: false, title: Ox._('Add Place')});
}
2011-05-29 17:44:48 +00:00
});
}
2011-05-29 17:44:48 +00:00
}
function clearPlace() {
var values = {
id: self.selectedPlace,
alternativeNames: [], geoname: '', type: '',
2012-02-05 01:56:23 +00:00
lat: null, lng: null,
south: null, west: null, north: null, east: null, area: null
};
2013-05-09 13:03:33 +00:00
self.$definePlaceButton.options({disabled: true, title: Ox._('Clearing...')});
self.options.editPlace(values, function() {
2012-09-10 12:36:43 +00:00
self.$map.removePlace();
2012-09-10 12:28:12 +00:00
self.$list.reloadList();
self.$findPlaceButton.show();
self.$placeFlag.hide();
hideForm();
2013-05-09 13:03:33 +00:00
self.$definePlaceButton.options({disabled: false, title: Ox._('Define Place')})
});
}
function decodeValues(place) {
return Ox.map(place, function(value) {
var type = Ox.typeOf(value);
return type == 'string' ? Ox.decodeHTMLEntities(value)
: type == 'array' ? Ox.map(value, function(value) {
return decodeValues(value);
})
: value;
});
}
function definePlace() {
2012-02-05 01:56:23 +00:00
self.$map.newPlace(); // this will call selectPlace, then editPlace
2013-05-09 13:03:33 +00:00
self.$definePlaceButton.options({title: Ox._('Clear Place')});
}
function encodeValues(place) {
return Ox.map(place, function(value) {
var type = Ox.typeOf(value);
return type == 'string' ? Ox.encodeHTMLEntities(value)
: type == 'array' ? Ox.map(value, function(value) {
return encodeValues(value);
})
: value;
});
}
function editPlace(keys) {
Ox.Log('Map', 'EDIT PLACE', keys, self.$placeForm.values())
2011-10-09 21:13:16 +00:00
var values = Ox.filter(self.$placeForm.values(), function(values, key) {
return keys.indexOf(key) > -1;
});
values.id = self.selectedPlace;
self.options.editPlace(encodeValues(values), function(result) {
Ox.Log('Map', 'EDIT PLACE::', result)
2012-02-20 18:31:45 +00:00
if (result.status.code == 200) {
if (
keys.indexOf(self.$list.options('sort')[0].key) > -1
|| (
self.options.mode == 'define'
&& (
keys.indexOf('name') > -1
|| keys.indexOf('alternativeNames') > -1
)
)
) {
self.$list.reloadList();
} else {
Ox.forEach(values, function(value, key) {
if (key != 'id') {
self.$list.value(values.id, key, value);
self.$map.value(values.id, key, value);
}
});
self.$list.value(values.id, 'matches', result.data.matches);
}
if (self.options.mode == 'define') {
self.$findPlaceButton.hide();
self.$placeFlag.show();
}
self.options.hasMatches && self.$matchesInput.value(result.data.matches);
if (self.options.mode == 'define') {
self.$definePlaceButton.options({
disabled: !result.data.matches,
2013-05-09 13:03:33 +00:00
title: Ox._('Clear Place')
2012-02-20 18:31:45 +00:00
});
self.$addPlaceButton.options({
disabled: !!result.data.matches
});
}
} else {
2012-02-20 18:31:45 +00:00
if (result.data.names.indexOf(self.$nameInput.value()) > -1) {
self.$nameInput.addClass('OxError');
}
self.$alternativeNamesInput.setErrors(result.data.names);
}
2011-05-29 17:44:48 +00:00
});
}
function findPlace() {
2012-02-20 18:31:45 +00:00
self.$map
//.options({find: ''})
.options({find: self.$list.value(self.options.selected, 'name')});
}
function hideForm() {
self.$placeForm.hide();
self.$areaKmInput.hide();
}
function getMatches(place) {
var names;
if (self.options.hasMatches) {
names = Ox.filter([place.name].concat(place.alternativeNames), function(name) {
return name !== '';
});
self.options.getMatches(names, function(matches) {
self.$matchesInput.value(matches);
});
}
}
2011-10-09 21:13:16 +00:00
function initList(data) {
2013-07-17 10:19:57 +00:00
self.$status.html(Ox.formatCount(data.items, 'Place'));
2011-10-09 21:13:16 +00:00
}
function openItem(data) {
selectItem(data);
self.$map.zoomToPlace(data.ids[0]);
}
function removeItem(data) {
var id = data.ids[0];
self.$list.value(id, 'type') && self.$map.removePlace(id);
// FIXME: events or callback functions??
2011-10-09 21:13:16 +00:00
that.triggerEvent('removeplace', {id: id});
}
function removePlace() {
var index;
2011-11-04 15:54:28 +00:00
Ox.Log('Map', 'REMOVE PLACE', self.selectedPlace, index)
if (!self.isAsync) {
2011-10-09 21:13:16 +00:00
// fixme: doesn't call self.options.removePlace!
index = Ox.getIndexById(self.options.places, self.selectedPlace);
self.options.selected = '';
self.options.places.splice(index, 1);
self.$list.options({items: Ox.clone(self.options.places)});
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({title: Ox._('Add Place')});
//setStatus();
}
// fixme: what is this? both options.removePlace and event removeplace??
if (self.isAsync) {
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({disabled: true, title: Ox._('Removing...')})
2011-05-29 17:44:48 +00:00
self.options.removePlace({id: self.selectedPlace}, function() {
self.options.selected = '';
2011-05-29 17:44:48 +00:00
self.$list.options({selected: []}).reloadList(true);
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.$matchesInput.hide();
2012-02-05 01:56:23 +00:00
self.options.mode == 'define' && self.$definePlaceButton.options({
disabled: true
});
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({disabled: false, title: Ox._('Add Place')});
2011-05-29 17:44:48 +00:00
});
}
self.$map.removePlace();
that.triggerEvent('removeplace', {id: self.selectedPlace});
}
2012-02-20 18:31:45 +00:00
function selectItem(data, place) {
// Select item in list
var isUndefined, selectedPlace;
self.options.selected = data.ids.length ? data.ids[0] : '';
2012-02-20 18:31:45 +00:00
place = place || (
self.options.selected
2012-06-30 15:01:43 +00:00
? self.$list.value(self.options.selected)
: {}
2012-02-20 18:31:45 +00:00
);
isUndefined = !!self.options.selected && !place.type;
selectedPlace = self.options.selected && !isUndefined
2012-02-20 18:31:45 +00:00
? self.options.selected : '';
self.$map.options({selected: selectedPlace});
selectedPlace && self.$map.panToPlace();
2012-02-20 18:31:45 +00:00
if (self.options.selected) {
self.options.mode == 'define'
&& self.$findPlaceButton[isUndefined ? 'show' : 'hide']();
self.$placeFlag.attr({
src: Ox.getFlagByGeoname(place.geoname || '', 16)
})[isUndefined ? 'hide' : 'show']();
self.$placeName.options({title: place.name || ''});
self.$placeTitle.show();
!isUndefined ? showForm(place) : hideForm();
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.$matchesInput.value(place.matches || 0).show();
self.options.mode == 'define' && self.$definePlaceButton.options({
disabled: !isUndefined && !place.matches,
title: isUndefined ? 'Define Place' : 'Clear Place'
}).show();
self.$addPlaceButton.options({
2012-02-20 18:31:45 +00:00
disabled: self.options.mode == 'define' && !!place.matches,
2013-05-09 13:03:33 +00:00
title: Ox._('Remove Place')
}).show();
2012-02-20 18:31:45 +00:00
} else {
self.$placeTitle.hide();
hideForm();
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.$matchesInput.hide();
self.options.mode == 'define' && self.$definePlaceButton.hide();
self.$addPlaceButton.hide();
}
2011-04-22 22:03:10 +00:00
}
2011-05-22 17:12:21 +00:00
function selectPlace(place) {
// Select place on map
2012-02-20 18:31:45 +00:00
var isResult = !!place.id && place.id[0] == '_',
isUndefined = !!self.options.selected
&& !self.$list.value(self.options.selected, 'type');
2012-02-20 18:31:45 +00:00
self.selectedPlace = place.id || '';
if (isResult && isUndefined) {
Ox.print('place.id', place.id, 'self.options.selected', self.options.selected, 'type', self.$list.value(self.options.selected));
2012-02-20 18:31:45 +00:00
// define undefined place
self.selectedPlace = self.options.selected;
place.name = self.$list.value(self.options.selected, 'name');
place.id = self.options.selected;
self.$map.addPlace(place);
self.$findPlaceButton.hide();
self.$placeFlag.attr({
src: Ox.getFlagByGeoname(place.geoname || '', 16)
}).show();
showForm(place);
2012-02-20 18:31:45 +00:00
editPlace([
'geoname', 'type',
'lat', 'lng',
'south', 'west', 'north', 'east', 'area'
]);
} else if (self.selectedPlace && isResult) {
// select result place
self.$list.options({selected: []});
2011-10-09 21:13:16 +00:00
self.$placeFlag.attr({
src: Ox.getFlagByGeoname(place.geoname || '', 16)
}).show();
self.$placeName.options({title: place.name || ''});
2011-05-24 06:15:44 +00:00
self.$placeTitle.show();
showForm(place);
2012-02-20 18:31:45 +00:00
if (self.options.hasMatches) {
self.$matchesInput.value('').show();
getMatches(place);
}
2012-02-20 18:31:45 +00:00
self.options.mode == 'define' && self.$definePlaceButton.hide();
2013-05-09 13:03:33 +00:00
self.$addPlaceButton.options({disabled: false, title: Ox._('Add Place')}).show();
2012-02-20 18:31:45 +00:00
} else if (!self.selectedPlace && !self.options.selected) {
// deselect result place
self.$placeFlag.hide();
2011-05-24 06:15:44 +00:00
self.$placeTitle.hide();
hideForm();
2012-02-20 18:31:45 +00:00
self.options.hasMatches && self.$matchesInput.hide();
} else if (!self.selectedPlace && isUndefined) {
// deselect triggered by selecting an undefined item,
// so do nothing
} else {
// select or deselect existing place
self.options.selected = self.selectedPlace;
self.$list.options({
selected: self.options.selected ? [self.options.selected] : []
});
// FIXME: list doesn't fire select event
selectItem({ids: self.$list.options('selected')}, place);
2011-05-24 06:15:44 +00:00
}
2011-04-22 22:03:10 +00:00
}
function showForm(place) {
self.$nameInput.removeClass('OxError');
self.$alternativeNamesInput.setErrors([]);
self.$placeForm.values(decodeValues(place)).show();
self.$areaKmInput.value(Ox.formatArea(place.area)).show();
}
2011-04-22 22:03:10 +00:00
function toFixed(val) {
return Ox.isNumber(val) ? val.toFixed(3) : '';
2011-04-22 22:03:10 +00:00
}
2012-01-15 15:05:17 +00:00
function toggleList() {
var list = self.$listSelect.options('value');
list == 'names' && !self.namesLoaded ? load() : toggle();
function load() {
self.options.names(function(data) {
self.$namesList.options({items: data});
self.namesLoaded = true;
toggle();
});
}
function toggle() {
self.$listPanel.replaceElement(1, self[list == 'places' ? '$list' : '$namesList']);
}
}
function updateList(key, value) {
var query = {
2012-05-24 07:45:33 +00:00
conditions: [].concat(
['all', 'name'].indexOf(key) > -1
? [{key: 'name', value: value, operator: '='}] : [],
['all', 'alternativeNames'].indexOf(key) > -1
? [{key: 'alternativeNames', value: value, operator: '='}] : [],
['all', 'geoname'].indexOf(key) > -1
? [{key: 'geoname', value: value, operator: '='}] : []
),
operator: key == 'all' ? '|' : '&'
};
self.$list.options({
items: function(data, callback) {
return pandora.api.findPlaces(Ox.extend(data, {
query: query
}), callback);
}
});
}
2011-05-16 10:49:48 +00:00
/*@
focusList <f> focusList
@*/
2011-04-22 22:03:10 +00:00
that.focusList = function() {
self.$list.gainFocus();
return that;
};
2011-04-22 22:03:10 +00:00
2011-05-16 10:49:48 +00:00
/*@
reloadList <f> reloadList
@*/
2011-04-22 22:03:10 +00:00
that.reloadList = function() {
self.$list.reloadList();
return that;
};
2011-04-22 22:03:10 +00:00
2011-05-16 10:49:48 +00:00
/*@
resizeMap <f> resizeMap
@*/
2011-04-22 22:03:10 +00:00
that.resizeMap = function() {
self.$map.resizeMap();
return that;
};
return that;
};