fix bugs in video editor; begin to implement new list map mode that allows for defining/clearing places

This commit is contained in:
rlx 2012-02-04 08:58:46 +00:00
parent ae82696600
commit 3c94f44a99
15 changed files with 437 additions and 255 deletions

View file

@ -612,7 +612,8 @@ OxArrayEditable
} }
.OxArrayEditable.OxArrayEditableTextarea .OxEditableElement { .OxArrayEditable.OxArrayEditableTextarea .OxEditableElement {
padding: 4px; padding: 4px;
border-top: 1px solid rgb(128, 128, 128); border-top-width: 1px;
border-top-style: solid;
} }
.OxArrayEditable.OxArrayEditableTextarea textarea { .OxArrayEditable.OxArrayEditableTextarea textarea {
padding: 4px; padding: 4px;
@ -1436,6 +1437,14 @@ Maps
height: 16px; height: 16px;
border-radius: 8px; border-radius: 8px;
} }
.OxTypeIcon {
width: 10px;
height: 10px;
border-width: 2px;
border-style: solid;
border-radius: 7px;
margin-left: -3px;
}
/* /*
================================================================================ ================================================================================

View file

@ -357,7 +357,7 @@ Ox.Calendar = function(options, self) {
.addClass('OxCalendarContainer') .addClass('OxCalendarContainer')
.css({ .css({
top: (self.options.showToolbar * 24) + 16 + 'px', top: (self.options.showToolbar * 24) + 16 + 'px',
bottom: (self.options.showZoombar * 16) + 'px' bottom: (self.options.showZoombar * 16) + 16 + 'px'
}) })
.bind({ .bind({
mouseleave: mouseleave, mouseleave: mouseleave,
@ -1015,7 +1015,7 @@ Ox.Calendar = function(options, self) {
marginLeft: -delta / getScrollbarFactor() + 'px' marginLeft: -delta / getScrollbarFactor() + 'px'
}, ms); }, ms);
if (!Ox.isUndefined(line)) { if (!Ox.isUndefined(line)) {
scrollTo((line + 1) * 16 - self.$container.height() / 2, true); scrollTo(line * 16 + 8 - self.$container.height() / 2, true);
} }
}; };
@ -1037,9 +1037,10 @@ Ox.Calendar = function(options, self) {
function renderCalendar() { function renderCalendar() {
self.contentHeight = Math.max( self.contentHeight = Math.max(
self.lineEvents.length * 16 + 16, // fixme: why +16 ? self.lineEvents.length * 16,
self.options.height - (self.options.showToolbar * 24) self.options.height - 32
// self.options.height - 56 // 24 + 16 + 16 - self.options.showZoombar * 16
- self.options.showToolbar * 24
); );
self.$content.css({height: self.contentHeight + 'px'}); self.$content.css({height: self.contentHeight + 'px'});
that.$element.find('.OxBackground').empty(); that.$element.find('.OxBackground').empty();
@ -1117,7 +1118,7 @@ Ox.Calendar = function(options, self) {
function scrollBy(delta) { function scrollBy(delta) {
scrollTo( scrollTo(
self.$container.$element[0].scrollTop self.$container.$element[0].scrollTop
+ delta * self.$container.height() / 2, true + delta * Math.round(self.$container.height() / 2), true
); );
} }
@ -1125,7 +1126,7 @@ Ox.Calendar = function(options, self) {
var containerHeight = self.$container.height(), var containerHeight = self.$container.height(),
scrollTop = self.$container.$element[0].scrollTop, scrollTop = self.$container.$element[0].scrollTop,
min = 0, min = 0,
max = Math.ceil(self.contentHeight - containerHeight / 2), max = self.contentHeight - containerHeight,
top = Ox.limit(top, min, max), top = Ox.limit(top, min, max),
delta = top - scrollTop, delta = top - scrollTop,
ms = 250 * Math.min(Math.abs(delta) / (containerHeight / 2), 1); ms = 250 * Math.min(Math.abs(delta) / (containerHeight / 2), 1);
@ -1144,14 +1145,11 @@ Ox.Calendar = function(options, self) {
if (id) { if (id) {
self.options.selected = id; self.options.selected = id;
$element = $element || getEventElementById(id); $element = $element || getEventElementById(id);
if ($element) { $element && $element.addClass('OxSelected');
$element.addClass('OxSelected'); panToSelected();
} else {
panToSelected();
}
event = Ox.getObjectById(self.options.events, id); event = Ox.getObjectById(self.options.events, id);
// fixme: map event should also be 'select', not 'selectplace'
setEventControls(event); setEventControls(event);
// fixme: map event should also be 'select', not 'selectplace'
that.triggerEvent('select', event); that.triggerEvent('select', event);
} else { } else {
if (self.options.selected !== '') { if (self.options.selected !== '') {
@ -1324,7 +1322,6 @@ Ox.Calendar = function(options, self) {
}; };
that.resizeCalendar = function() { that.resizeCalendar = function() {
Ox.print('RESIZE CALENDAR')
self.options.width = that.width(); self.options.width = that.width();
self.options.height = that.height(); self.options.height = that.height();
self.options.showZoombar && self.$zoomInput.options({size: self.options.width}); self.options.showZoombar && self.$zoomInput.options({size: self.options.width});

View file

@ -1,4 +1,5 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript // vim: et:ts=4:sw=4:sts=4:ft=javascript
'use strict';
Ox.GarbageCollection = (function() { Ox.GarbageCollection = (function() {
@ -43,4 +44,4 @@ Ox.GarbageCollection = (function() {
return that; return that;
}()); }());

View file

@ -155,7 +155,8 @@ Ox.Form = function(options, self) {
return self.formIsValid; return self.formIsValid;
}; };
that.values = function() { // fixme: can this be private? that.values = function() {
// FIXME: this should accept a single string argument to get a single value
/* /*
get/set form values get/set form values
call without arguments to get current form values call without arguments to get current form values

View file

@ -10,8 +10,9 @@ Ox.ListMap <f:Ox.Element> ListMap object
options <o> Options object options <o> Options object
height <n|256> Height in px height <n|256> Height in px
labels <b|false> If true, show labels labels <b|false> If true, show labels
mode <s|'add'> Mode ('add' or 'define')
places <a|f|null> Array of places, or function that returns places places <a|f|null> Array of places, or function that returns places
selected <a|[]> Selected places selected <s|''> Id of the selected place
width <n|256> Width in px width <n|256> Width in px
self <o> Shared private variable self <o> Shared private variable
@*/ @*/
@ -23,9 +24,11 @@ Ox.ListMap = function(options, self) {
.defaults({ .defaults({
addPlace: null, addPlace: null,
editPlace: null, editPlace: null,
collapsible: false,
getMatches: null, getMatches: null,
height: 256, height: 256,
labels: false, labels: false,
mode: 'add',
pageLength: 100, pageLength: 100,
places: null, places: null,
removePlace: null, removePlace: null,
@ -37,7 +40,6 @@ Ox.ListMap = function(options, self) {
width: 256 width: 256
}) })
.options(options || {}) .options(options || {})
.addClass('OxListMap')
.css({ .css({
width: self.options.width + 'px', width: self.options.width + 'px',
height: self.options.height + 'px' height: self.options.height + 'px'
@ -45,6 +47,21 @@ Ox.ListMap = function(options, self) {
self.isAsync = Ox.isFunction(self.options.places); 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 = {
10000: 8, // 100 x 100 m
10000000000: 10 // 100 x 100 km
};
self.columns = [ self.columns = [
{ {
addable: false, // fixme: implement addable: false, // fixme: implement
@ -56,26 +73,78 @@ Ox.ListMap = function(options, self) {
}, },
{ {
format: function(value, data) { format: function(value, data) {
return data.geoname ? $('<img>') return data.geoname
.attr({ ? $('<img>')
src: Ox.getFlagByGeoname(data.geoname, 16) .attr({
}) src: Ox.getFlagByGeoname(data.geoname, 16)
.css({ })
width: '14px', .css({
height: '14px', width: '14px',
borderRadius: '4px', height: '14px',
marginLeft: '-3px', borderRadius: '4px',
marginTop: 0 marginLeft: '-3px',
}) : ''; marginTop: 0
})
: '';
}, },
id: 'countryCode', id: 'countryCode',
map: function(value) {
var names = value.split(', ');
if (!Ox.getCountryByGeoname(names[names.length - 1])) {
names.push('~');
}
return names.reverse().join(', ');
},
operator: '+',
resizable: false, // fixme: implement resizable: false, // fixme: implement
title: 'Flag', title: 'Flag',
titleImage: 'flag', titleImage: 'flag',
tooltip: function(data) {
return Ox.toTitleCase(data.geoname || '')
},
visible: true, visible: true,
width: 16 width: 16
}, },
{ {
format: function(value, data) {
var iconSize = 6;
Ox.forEach(self.areaSize, function(size, area) {
if (data.area >= area) {
iconSize = size;
} else {
return false;
}
});
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: '+',
title: 'Type',
titleImage: 'icon',
tooltip: function(data) {
return Ox.toTitleCase(data.type || '');
},
visible: true,
width: 16
},
{
format: function(value, data) {
return data.type
? value
: $('<span>').addClass('OxWarning').html(value)
},
id: 'name', id: 'name',
operator: '+', operator: '+',
removable: false, removable: false,
@ -99,21 +168,29 @@ Ox.ListMap = function(options, self) {
var names = value.split(', '); var names = value.split(', ');
if (!Ox.getCountryByGeoname(names[names.length - 1])) { if (!Ox.getCountryByGeoname(names[names.length - 1])) {
names.push('~'); names.push('~');
} }
return names.reverse().join(', '); return names.reverse().join(', ');
}, },
operator: '+', operator: '+',
title: 'Geoname', title: 'Geoname',
visible: true, visible: false,
width: 192 width: 192
}, },
{ {
format: function(value) { align: 'right',
return Ox.toTitleCase(value); format: toFixed,
}, id: 'lat',
id: 'type',
operator: '+', operator: '+',
title: 'Type', title: 'Latitude',
visible: true,
width: 64
},
{
align: 'right',
format: toFixed,
id: 'lng',
operator: '+',
title: 'Longitude',
visible: true, visible: true,
width: 64 width: 64
}, },
@ -124,7 +201,7 @@ Ox.ListMap = function(options, self) {
operator: '+', operator: '+',
title: 'South', title: 'South',
visible: false, visible: false,
width: 96 width: 64
}, },
{ {
align: 'right', align: 'right',
@ -132,7 +209,7 @@ Ox.ListMap = function(options, self) {
operator: '+', operator: '+',
title: 'West', title: 'West',
visible: false, visible: false,
width: 96 width: 64
}, },
{ {
align: 'right', align: 'right',
@ -141,7 +218,7 @@ Ox.ListMap = function(options, self) {
operator: '+', operator: '+',
title: 'North', title: 'North',
visible: false, visible: false,
width: 96 width: 64
}, },
{ {
align: 'right', align: 'right',
@ -150,25 +227,7 @@ Ox.ListMap = function(options, self) {
operator: '+', operator: '+',
title: 'East', title: 'East',
visible: false, visible: false,
width: 96 width: 64
},
{
align: 'right',
format: toFixed,
id: 'lat',
operator: '+',
title: 'Latitude',
visible: true,
width: 96
},
{
align: 'right',
format: toFixed,
id: 'lng',
operator: '+',
title: 'Longitude',
visible: true,
width: 96
}, },
{ {
align: 'right', align: 'right',
@ -267,6 +326,7 @@ Ox.ListMap = function(options, self) {
columnsVisible: true, columnsVisible: true,
//items: Ox.clone(self.options.places), //items: Ox.clone(self.options.places),
items: self.options.places, items: self.options.places,
keys: ['area', 'geoname'], // needed for icon and flag
max: 1, max: 1,
min: 0, min: 0,
pageLength: self.options.pageLength, pageLength: self.options.pageLength,
@ -353,7 +413,20 @@ Ox.ListMap = function(options, self) {
}); });
self.$placeTitle = $('<div>') self.$placeTitle = $('<div>')
.hide() .hide()
.appendTo(self.$placeTitlebar) .appendTo(self.$placeTitlebar);
if (self.options.mode == 'define') {
self.$findPlaceButton = Ox.Button({
title: 'find',
tooltip: 'Find',
type: 'image'
})
.css({float: 'left', margin: '4px'})
.bindEvent({
click: findPlace
})
.hide()
.appendTo(self.$placeTitle);
}
self.$placeFlag = $('<img>') self.$placeFlag = $('<img>')
.addClass('OxFlag') .addClass('OxFlag')
.attr({ .attr({
@ -438,6 +511,7 @@ Ox.ListMap = function(options, self) {
country = Ox.getCountryByGeoname(geoname), country = Ox.getCountryByGeoname(geoname),
countryCode = country ? country.code : '', countryCode = country ? country.code : '',
isResult = self.selectedPlace[0] == '_'; isResult = self.selectedPlace[0] == '_';
Ox.print('CHANGE', geoname, country, countryCode, self.isAsync);
self.$placeFlag.attr({ self.$placeFlag.attr({
src: Ox.getFlagByGeoname(geoname, 16) src: Ox.getFlagByGeoname(geoname, 16)
}); });
@ -564,9 +638,9 @@ Ox.ListMap = function(options, self) {
self.$newPlaceButton = Ox.Button({ self.$newPlaceButton = Ox.Button({
title: 'New Place', title: 'New Place',
width: 96 width: 70
}) })
.css({float: 'left', margin: '4px 2px 4px 4px'}) .css({float: 'left', margin: '4px'})
.bindEvent({ .bindEvent({
click: function() { click: function() {
self.$map.newPlace(); self.$map.newPlace();
@ -574,14 +648,14 @@ Ox.ListMap = function(options, self) {
}) })
.appendTo(self.$placeStatusbar); .appendTo(self.$placeStatusbar);
self.$placeButton = Ox.Button({ self.$addPlaceButton = Ox.Button({
title: 'Add Place', tooltip: 'Add Place',
width: 96 width: 90
}) })
.css({float: 'right', margin: '4px 4px 4px 2px'}) .css({float: 'right', margin: '4px'})
.bindEvent({ .bindEvent({
click: function() { click: function() {
if (self.$placeButton.options('title') == 'Add Place') { if (this.options('title') == 'Add Place') {
addPlace(); addPlace();
} else { } else {
removePlace(); removePlace();
@ -591,6 +665,25 @@ Ox.ListMap = function(options, self) {
.hide() .hide()
.appendTo(self.$placeStatusbar); .appendTo(self.$placeStatusbar);
if (self.options.mode == 'define') {
self.$definePlaceButton = Ox.Button({
title: 'Define Place',
width: 80
})
.css({float: 'right', margin: '4px 0 4px 0'})
.bindEvent({
click: function() {
if (this.options('title') == 'Define Place') {
definePlace();
} else {
clearPlace();
}
}
})
.hide()
.appendTo(self.$placeStatusbar);
}
/* /*
self.$revertButton = Ox.Button({ self.$revertButton = Ox.Button({
title: 'Revert', title: 'Revert',
@ -625,7 +718,7 @@ Ox.ListMap = function(options, self) {
that.$element = Ox.SplitPanel({ that.$element = Ox.SplitPanel({
elements: [ elements: [
{ {
collapsible: true, collapsible: self.options.collapsible,
element: self.$listPanel = Ox.SplitPanel({ element: self.$listPanel = Ox.SplitPanel({
elements: [ elements: [
{ {
@ -647,10 +740,15 @@ Ox.ListMap = function(options, self) {
size: 256 size: 256
}, },
{ {
element: self.$map, element: self.$map
.bindEvent({
resize: function() {
self.$map.resizeMap();
}
}),
}, },
{ {
collapsible: true, collapsible: self.options.collapsible,
element: Ox.SplitPanel({ element: Ox.SplitPanel({
elements: [ elements: [
{ {
@ -674,15 +772,19 @@ Ox.ListMap = function(options, self) {
self.$placeFormItems.forEach(function($item) { self.$placeFormItems.forEach(function($item) {
$item.options({width: data.size - 16}); $item.options({width: data.size - 16});
}); });
self.$areaKmInput.options({width: data.size - 16});
self.$matchesInput && self.$matchesInput.options({width: data.size - 16});
} }
}), }),
resizable: true, resizable: true,
resize: [204, 256, 384], resize: [256, 384],
size: 256 size: 256
} }
], ],
orientation: 'horizontal' orientation: 'horizontal'
}).$element })
.addClass('OxListMap')
.$element
); );
function addPlace() { function addPlace() {
@ -698,19 +800,19 @@ Ox.ListMap = function(options, self) {
selected: [place.id] selected: [place.id]
}); });
self.$map.addPlace(place); self.$map.addPlace(place);
self.$placeButton.options({title: 'Remove Place'}); self.$addPlaceButton.options({title: 'Remove Place'});
//setStatus(); //setStatus();
} }
//that.triggerEvent('addplace', {place: place}); //that.triggerEvent('addplace', {place: place});
if (self.isAsync) { if (self.isAsync) {
self.$placeButton.options({disabled: true, title: 'Adding Place'}); self.$addPlaceButton.options({disabled: true, title: 'Adding...'});
self.options.addPlace(place, function(result) { self.options.addPlace(place, function(result) {
if (result.status.code == 200) { if (result.status.code == 200) {
place.id = result.data.id; place.id = result.data.id;
self.selectedPlace = place.id; self.selectedPlace = place.id;
self.$list.reloadList().options({selected: [place.id]}); self.$list.reloadList().options({selected: [place.id]});
self.$map.addPlace(place); self.$map.addPlace(place);
self.$placeButton.options({disabled: false, title: 'Remove Place'}); self.$addPlaceButton.options({disabled: false, title: 'Remove Place'});
} else { } else {
if (result.data.names) { if (result.data.names) {
if (result.data.names.indexOf(self.$nameInput.value()) > -1) { if (result.data.names.indexOf(self.$nameInput.value()) > -1) {
@ -721,13 +823,37 @@ Ox.ListMap = function(options, self) {
if (result.data.geoname) { if (result.data.geoname) {
self.$geonameInput.addClass('OxError'); self.$geonameInput.addClass('OxError');
} }
self.$placeButton.options({disabled: false, title: 'Add Place'}); self.$addPlaceButton.options({disabled: false, title: 'Add Place'});
} }
}); });
} }
} }
function clearPlace() {
var values = {
id: self.selectedPlace,
alternativeNames: [], geoname: '', type: '',
latitude: null, longitude: null,
south: null, west: null, north: null, east: null
};
self.$definePlaceButton.options({disabled: true, title: 'Clearing...'});
self.options.editPlace(values, function() {
self.$list.reloadList();
self.$map.removePlace();
self.$findPlaceButton.show();
self.$placeFlag.hide();
self.$placeForm.hide();
self.$definePlaceButton.options({disabled: false, title: 'Define Place'})
});
}
function definePlace() {
self.$map.newPlace();
self.$definePlaceButton.options({title: 'Clear Place'})
}
function editPlace(keys) { function editPlace(keys) {
Ox.print('EDIT PLACE', keys, self.$placeForm.values())
var values = Ox.filter(self.$placeForm.values(), function(values, key) { var values = Ox.filter(self.$placeForm.values(), function(values, key) {
return keys.indexOf(key) > -1; return keys.indexOf(key) > -1;
}); });
@ -749,6 +875,12 @@ Ox.ListMap = function(options, self) {
} }
} }
function findPlace() {
self.$map.options({
find: self.$list.value(self.selectedPlace).name
});
}
function initList(data) { function initList(data) {
self.$status.html( self.$status.html(
Ox.formatNumber(data.items) + ' Place' + ( Ox.formatNumber(data.items) + ' Place' + (
@ -777,52 +909,100 @@ Ox.ListMap = function(options, self) {
index = Ox.getIndexById(self.options.places, self.selectedPlace); index = Ox.getIndexById(self.options.places, self.selectedPlace);
self.options.places.splice(index, 1); self.options.places.splice(index, 1);
self.$list.options({items: Ox.clone(self.options.places)}); self.$list.options({items: Ox.clone(self.options.places)});
self.$addPlaceButton.options({title: 'Add Place'});
//setStatus(); //setStatus();
} }
// fixme: what is this? both options.removePlace and event removeplace?? // fixme: what is this? both options.removePlace and event removeplace??
if (self.isAsync) { if (self.isAsync) {
self.$addPlaceButton.options({disabled: true, title: 'Removing...'})
self.options.removePlace({id: self.selectedPlace}, function() { self.options.removePlace({id: self.selectedPlace}, function() {
self.$list.options({selected: []}).reloadList(true); self.$list.options({selected: []}).reloadList(true);
self.$addPlaceButton.options({disabled: false, title: 'Add Place'})
}); });
} }
self.$map.removePlace(); self.$map.removePlace();
self.$placeButton.options({title: 'Add Place'});
that.triggerEvent('removeplace', {id: self.selectedPlace}); that.triggerEvent('removeplace', {id: self.selectedPlace});
} }
function selectItem(data) { function selectItem(data) {
var id = data.ids.length ? data.ids[0] : null; // Select item in list
self.$map.options({selected: id}); var isUndefined, selectedPlace;
id && self.$map.panToPlace(); self.options.selected = data.ids.length ? data.ids[0] : '';
isUndefined = !!self.options.selected
&& !self.$list.value(self.options.selected, 'type');
selectedPlace = self.options.selected && !isUndefined
? self.options.selected : null;
self.$map.options({selected: selectedPlace});
selectedPlace && self.$map.panToPlace();
if (isUndefined) {
self.selectedPlace = self.options.selected;
self.$findPlaceButton.show();
self.$placeFlag.hide();
self.$placeName.options({
title: self.$list.value(self.options.selected, 'name')
});
self.$placeTitle.show();
self.$definePlaceButton.options({
title: 'Define Place'
}).show();
self.$addPlaceButton.options({
title: 'Remove Place'
}).show();
}
} }
function selectPlace(place) { function selectPlace(place) {
var isResult = place.id && place.id[0] == '_'; // Select place on map
self.$list.options({ Ox.print('selectPlace', place)
selected: place.id && !isResult ? [place.id] : [] var isResult, isUndefined;
}); self.selectedPlace = place.id || null;
if (place.id) { isResult = !!place.id && place.id[0] == '_';
//isResult && self.options.places.push(place); isUndefined = !!self.options.selected
self.selectedPlace = place.id; && !self.$list.value(self.options.selected, 'type');
self.$placeFlag.attr({ Ox.print('isResult', isResult, 'isUndefined', isUndefined, self.options.selected)
src: Ox.getFlagByGeoname(place.geoname, 16) if (!isUndefined) {
self.$list.options({
selected: place.id && !isResult ? [place.id] : []
}); });
self.$placeName.options({title: place.geoname || ''}); }
if (place.id) {
if (isResult && isUndefined) {
place.name = self.$list.value(self.selectedPlace, 'name');
}
self.options.mode == 'define' && self.$findPlaceButton.hide();
self.$placeFlag.attr({
src: Ox.getFlagByGeoname(place.geoname || '', 16)
}).show();
self.$placeName.options({title: place.name || ''});
self.$placeTitle.show(); self.$placeTitle.show();
self.$areaKmInput.value(Ox.formatArea(place.area));
self.$placeForm.values(place).show(); self.$placeForm.values(place).show();
self.$placeButton.options({title: isResult ? 'Add Place' : 'Remove Place'}).show(); self.$areaKmInput.value(Ox.formatArea(place.area));
updateMatches(); updateMatches();
self.options.mode == 'define' && self.$definePlaceButton.options({
title: isUndefined && !isResult ? 'Define Place' : 'Clear Place'
}).show();
self.$addPlaceButton.options({
title: isResult ? 'Add Place' : 'Remove Place'
}).show();
if (isResult && isUndefined) {
Ox.print('???? s.o.s s.sP', self.options.selected, self.selectedPlace)
self.selectedPlace = self.options.selected;
editPlace([
'geoname', 'type',
'latitude', 'longitude',
'south', 'west', 'north', 'east', 'area'
]);
}
} else { } else {
self.selectedPlace = null;
self.$placeTitle.hide(); self.$placeTitle.hide();
self.$placeForm.hide(); self.$placeForm.hide();
self.$placeButton.hide(); self.options.mode == 'define' && self.$definePlaceButton.hide();
self.$addPlaceButton.hide();
} }
} }
function toFixed(val) { function toFixed(val) {
return Ox.isNumber(val) ? val.toFixed(8) : val; // fixme: why can a string be passed ?? return Ox.isNumber(val) ? val.toFixed(3) : '';
} }
function toggleList() { function toggleList() {

View file

@ -849,7 +849,8 @@ Ox.Map = function(options, self) {
}); });
if (self.options.find) { if (self.options.find) {
self.$findInput.value(self.options.find) self.$findInput
.value(self.options.find)
.triggerEvent('submit', {value: self.options.find}); .triggerEvent('submit', {value: self.options.find});
} else { } else {
if (self.options.selected) { if (self.options.selected) {
@ -1388,7 +1389,11 @@ Ox.Map = function(options, self) {
} }
self.setOption = function(key, value) { self.setOption = function(key, value) {
if (key == 'height' || key == 'width') { if (key == 'find') {
self.$findInput
.value(self.options.find)
.triggerEvent('submit', {value: self.options.find});
} else if (key == 'height' || key == 'width') {
that.$element.css(key, value + 'px'); that.$element.css(key, value + 'px');
that.resizeMap(); that.resizeMap();
} else if (key == 'places') { } else if (key == 'places') {

View file

@ -209,7 +209,7 @@ Ox.MapMarker = function(options) {
} }
that.size = 8; that.size = 8;
Ox.forEach(areaSize, function(size, area) { Ox.forEach(areaSize, function(size, area) {
if (that.place.area > area) { if (that.place.area >= area) {
that.size = size; that.size = size;
} else { } else {
return false; return false;

View file

@ -396,9 +396,8 @@ Ox.AnnotationFolder = function(options, self) {
} }
function isDefined(item) { function isDefined(item) {
return self.options.type == 'event' return !!item[self.options.type]
? item.event.start !== '' && !!item[self.options.type].type;
: item.place.lat !== null;
} }
function removeAnnotation(data) { function removeAnnotation(data) {

View file

@ -281,6 +281,7 @@ Ox.AnnotationPanel = function(options, self) {
} }
function selectAnnotation(data, index) { function selectAnnotation(data, index) {
Ox.print('selectAnnotation', index)
self.options.selected = data.id; self.options.selected = data.id;
if (data.id) { if (data.id) {
self.$folder.forEach(function($folder, i) { self.$folder.forEach(function($folder, i) {
@ -288,25 +289,6 @@ Ox.AnnotationPanel = function(options, self) {
}); });
scrollToSelected(self.options.layers[index].type); scrollToSelected(self.options.layers[index].type);
} }
/*
if (data.top) {
data.bottom = data.top + data.height;
height = self.$folders.height();
top = self.$folders.offset().top;
scrollTop = self.$folders.scrollTop();
if (data.top < top || data.bottom > height) {
if (data.top < top) {
Ox.print('top scrollTop', data.top, scrollTop)
scrollTop += data.top - top;
} else {
scrollTop += data.bottom - top - height;
}
self.$folders.animate({
scrollTop: scrollTop + 'px'
}, 0);
}
}
*/
that.triggerEvent('select', data); that.triggerEvent('select', data);
} }

View file

@ -73,6 +73,9 @@ Ox.VideoEditor = function(options, self) {
}, },
key_alt_shift_right: function() { key_alt_shift_right: function() {
}, },
key_b: function() {
selectAnnotation(getNextAnnotation('annotation', -1));
},
key_backslash: function() { key_backslash: function() {
selectAnnotation(); selectAnnotation();
}, },
@ -112,7 +115,7 @@ Ox.VideoEditor = function(options, self) {
}); });
}, },
key_g: function() { key_g: function() {
self.results.length && selectAnnotation(getNextResult(1)); self.results.length && selectAnnotation(getNextAnnotation('result', 1));
}, },
key_i: function() { key_i: function() {
setPoint('in', self.options.position); setPoint('in', self.options.position);
@ -123,6 +126,9 @@ Ox.VideoEditor = function(options, self) {
key_minus: function() { key_minus: function() {
self.options.videoSize == 'large' && toggleSize(); self.options.videoSize == 'large' && toggleSize();
}, },
key_n: function() {
selectAnnotation(getNextAnnotation('annotation', 1));
},
key_o: function() { key_o: function() {
setPoint('out', self.options.position); setPoint('out', self.options.position);
}, },
@ -146,7 +152,7 @@ Ox.VideoEditor = function(options, self) {
movePositionBy(self.options.duration); movePositionBy(self.options.duration);
}, },
key_shift_g: function() { key_shift_g: function() {
self.results.length && selectAnnotation(getNextResult(-1)); self.results.length && selectAnnotation(getNextAnnotation('result', -1));
}, },
key_shift_left: function() { key_shift_left: function() {
movePositionBy(-1); movePositionBy(-1);
@ -183,9 +189,12 @@ Ox.VideoEditor = function(options, self) {
self.$player = []; self.$player = [];
self.$timeline = []; self.$timeline = [];
self.annotations = getAnnotations();
self.controlsHeight = 16; self.controlsHeight = 16;
self.editing = false; self.editing = false;
self.margin = 8; self.margin = 8;
self.positions = getPositions();
self.results = [];
self.words = getWords(); self.words = getWords();
Ox.print('VIDEO EDITOR OPTIONS', self.options) Ox.print('VIDEO EDITOR OPTIONS', self.options)
@ -354,7 +363,7 @@ Ox.VideoEditor = function(options, self) {
}); });
self.$keyboardShortcuts = $('<div>').css({margin: '16px'}); self.$keyboardShortcuts = $('<div>').css({margin: '16px'});
[ Ox.merge([
{key: Ox.UI.symbols.space, action: 'Play/Pause'}, {key: Ox.UI.symbols.space, action: 'Play/Pause'},
{key: 'P', action: 'Play In to Out'}, {key: 'P', action: 'Play In to Out'},
{key: '0', action: 'Mute/Unmute'}, {key: '0', action: 'Mute/Unmute'},
@ -375,17 +384,19 @@ Ox.VideoEditor = function(options, self) {
{key: '[', action: 'Go to Previous Annotation'}, {key: '[', action: 'Go to Previous Annotation'},
{key: ']', action: 'Go to Next Annotation'}, {key: ']', action: 'Go to Next Annotation'},
{key: '\\', action: 'Select Current Annotation'}, {key: '\\', action: 'Select Current Annotation'},
{key: 'B', action: 'Select Previous Annotation'},
{key: 'N', action: 'Select Next Annotation'},
{key: '<', action: 'Go to Previous Cut'}, {key: '<', action: 'Go to Previous Cut'},
{key: '>', action: 'Go to Next Cut'}, {key: '>', action: 'Go to Next Cut'},
{key: '/', action: 'Select Current Cut'}, {key: '/', action: 'Select Current Cut'},
{key: 'F', action: 'Find'}, {key: 'F', action: 'Find'},
{key: Ox.UI.symbols.shift + 'G', action: 'Go to Previous Result'}, {key: Ox.UI.symbols.shift + 'G', action: 'Go to Previous Result'},
{key: 'G', action: 'Go to Next Result'}, {key: 'G', action: 'Go to Next Result'},
{key: 'S', action: 'Select Current Annotation'}, {key: Ox.UI.symbols['return'], action: 'Edit/Submit'},
{key: 'E', action: 'Edit Selected Annotation'}, {key: Ox.UI.symbols.escape, action: 'Cancel/Deselect'}
{key: Ox.UI.symbols['return'], action: 'Submit'}, ], self.options.layers.map(function(layer, i) {
{key: Ox.UI.symbols.escape, action: 'Cancel'} return {key: i + 1, action: 'Add ' + layer.item};
].forEach(function(shortcut) { })).forEach(function(shortcut) {
self.$keyboardShortcuts.append( self.$keyboardShortcuts.append(
$('<div>').css({display: 'table-row'}) $('<div>').css({display: 'table-row'})
.append( .append(
@ -532,7 +543,7 @@ Ox.VideoEditor = function(options, self) {
.css({float: 'right'}) .css({float: 'right'})
.bindEvent({ .bindEvent({
click: function() { click: function() {
selectAnnotation(getNextResult(1)); selectAnnotation(getNextAnnotation('result', 1));
} }
}) })
.appendTo(self.$menubar); .appendTo(self.$menubar);
@ -547,7 +558,7 @@ Ox.VideoEditor = function(options, self) {
.css({float: 'right'}) .css({float: 'right'})
.bindEvent({ .bindEvent({
click: function() { click: function() {
selectAnnotation(getNextResult(-1)); selectAnnotation(getNextAnnotation('result', -1));
} }
}) })
.appendTo(self.$menubar); .appendTo(self.$menubar);
@ -614,17 +625,7 @@ Ox.VideoEditor = function(options, self) {
that.triggerEvent('info', data); that.triggerEvent('info', data);
}, },
paused: togglePaused, paused: togglePaused,
remove: function(data) { remove: removeAnnotation,
Ox.print('REMOVE EVENT REACHED EDITOR', data)
var layer = Ox.getObjectById(self.options.layers, data.layer),
index = Ox.getIndexById(layer.items, data.id);
updateWords('remove');
layer.items.splice(index, 1);
self.editing = false;
self.options.selected = '';
setTimelineState();
that.triggerEvent('removeannotation', data);
},
resize: resizeAnnotations, resize: resizeAnnotations,
resizeend: resizeendAnnotations, resizeend: resizeendAnnotations,
resizecalendar: function(data) { resizecalendar: function(data) {
@ -736,37 +737,17 @@ Ox.VideoEditor = function(options, self) {
out: item.out out: item.out
} : null; } : null;
}); });
}))).sort(function(a, b) { }))).sort(sortAnnotations);
var ret = 0;
if (a['in'] < b['in']) {
ret = -1;
} else if (a['in'] > b['in']) {
ret = 1;
} else if (a.out < b.out) {
ret = -1;
} else if (a.out > b.out) {
ret = 1;
}
return ret;
});
} }
return results; return results;
} }
function getAnnotation() { function getAnnotation() {
// Get annotation at current position // Get annotation at current position
var annotations = []; var annotations = self.annotations.filter(function(annotation) {
self.options.layers.forEach(function(layer) { return annotation['in'] <= self.options.position
layer.items.forEach(function(item) { && annotation.out >= self.options.position
if ( }).sort(function(a, b) {
item['in'] <= self.options.position
&& item.out >= self.options.position
) {
annotations.push(item);
}
});
});
annotations.sort(function(a, b) {
var aValue = self.options.position - a['in'], var aValue = self.options.position - a['in'],
bValue = self.options.position - b['in'], bValue = self.options.position - b['in'],
ret = 0; ret = 0;
@ -788,6 +769,12 @@ Ox.VideoEditor = function(options, self) {
return annotations.length ? annotations[0] : {id: ''}; return annotations.length ? annotations[0] : {id: ''};
} }
function getAnnotations() {
return Ox.flatten(Ox.merge(self.options.layers.map(function(layer) {
return layer.items;
}))).sort(sortAnnotations);
}
function getAnnotationValue(annotationId) { function getAnnotationValue(annotationId) {
var found = false, value; var found = false, value;
Ox.forEach(self.options.layers, function(layer, i) { Ox.forEach(self.options.layers, function(layer, i) {
@ -803,26 +790,43 @@ Ox.VideoEditor = function(options, self) {
return value; return value;
} }
function getNextAnnotation(type, direction) {
// type can be 'annotation' or 'result
var annotation,
annotations = type == 'annotation' ? self.annotations : self.results,
index,
position;
if (self.options.selected) {
index = Ox.getIndexById(annotations, self.options.selected);
if (index > -1 && self.options.position == annotations[index]['in']) {
annotation = annotations[Ox.mod(index + direction, annotations.length)];
}
}
if (!annotation) {
position = getNextPosition(type, direction);
annotations = annotations.filter(function(annotation) {
return annotation['in'] == position;
});
annotation = annotations[direction == 1 ? 0 : annotations.length - 1];
}
return annotation;
}
// fixme: why not goToNextPosition()? // fixme: why not goToNextPosition()?
function getNextPosition(type, direction) { function getNextPosition(type, direction) {
// type can be 'annotation', 'cut' or 'result'
var found = false, var found = false,
position = 0, position = 0,
positions; positions;
if (type == 'annotation') { if (type == 'annotation') {
positions = Ox.sort(Ox.unique(Ox.flatten( positions = self.positions;
self.options.layers.map(function(layer) {
return layer.items.map(function(item) {
return item['in'];
});
})
)));
} else if (type == 'cut') { } else if (type == 'cut') {
positions = Ox.merge(0, self.options.cuts, self.options.duration); positions = Ox.merge(0, self.options.cuts, self.options.duration);
}/* else if (type == 'result') { } else if (type == 'result') {
positions = self.results.map(function(v) { positions = Ox.unique(self.results.map(function(result) {
return v['in']; return result['in'];
}); }));
}*/ }
direction == -1 && positions.reverse(); direction == -1 && positions.reverse();
Ox.forEach(positions, function(v) { Ox.forEach(positions, function(v) {
if ( if (
@ -842,69 +846,12 @@ Ox.VideoEditor = function(options, self) {
return position; return position;
} }
function getNextResult(direction) { function getPositions() {
var found = false, index, result; return Ox.unique(self.annotations.map(function(annotation) {
if ( return annotation['in'];
self.currentResult }));
&& self.options.position == Ox.getObjectById(self.results, self.currentResult)['in']
) {
index = Ox.getIndexById(self.results, self.currentResult);
result = self.results[Ox.mod(index + direction, self.results.length)];
} else {
direction == -1 && self.results.reverse();
Ox.forEach(self.results, function(v) {
if (
direction == 1
? v['in'] > self.options.position
: v['in'] < self.options.position
) {
result = v;
found = true;
return false;
}
});
direction == -1 && self.results.reverse();
if (!found) {
Ox.print('!found', direction, self.results[direction == 1 ? 0 : results.length - 1])
result = self.results[direction == 1 ? 0 : self.results.length - 1];
}
}
self.currentResult = result.id;
return result;
} }
/*
function getPoints(type) {
var found = false,
points,
positions = [];
if (type == 'annotation') {
} else if (type == 'cut') {
positions = self.options.cuts;
} else if (type == 'result') {
// ...
} else if (type == 'subtitle') {
// FIXME: remove? annotation?
self.options.subtitles.forEach(function(v, i) {
positions.push(v['in']);
positions.push(v.out);
});
}
positions.indexOf(0) == -1 && positions.unshift(0);
positions.indexOf(self.options.duration) == -1
&& positions.push(self.options.duration);
Ox.forEach(positions, function(v, i) {
if (v > self.options.position) {
points = [positions[i - 1], positions[i]];
found = true;
return false;
}
});
return points;
}
*/
function getSizes(scrollbarIsVisible) { function getSizes(scrollbarIsVisible) {
var scrollbarWidth = Ox.UI.SCROLLBAR_SIZE, var scrollbarWidth = Ox.UI.SCROLLBAR_SIZE,
contentWidth = self.options.width contentWidth = self.options.width
@ -1005,6 +952,20 @@ Ox.VideoEditor = function(options, self) {
self.$player[0].playInToOut(); self.$player[0].playInToOut();
} }
function removeAnnotation(data) {
Ox.print('REMOVE EVENT REACHED EDITOR', data)
var layer = Ox.getObjectById(self.options.layers, data.layer),
index = Ox.getIndexById(layer.items, data.id);
updateWords('remove');
layer.items.splice(index, 1);
self.annotations = getAnnotations();
self.positions = getPositions();
self.editing = false;
self.options.selected = '';
setTimelineState();
that.triggerEvent('removeannotation', data);
}
function resizeAnnotations(data) { function resizeAnnotations(data) {
self.options.annotationsSize = data.size; self.options.annotationsSize = data.size;
setSizes(); setSizes();
@ -1137,18 +1098,35 @@ Ox.VideoEditor = function(options, self) {
: self.options.selected ? 'selected' : self.options.selected ? 'selected'
: 'default' : 'default'
}); });
//Ox.print('SET STATE', self.$timeline[1].options('state')) }
function sortAnnotations(a, b) {
var ret = 0;
if (a['in'] < b['in']) {
ret = -1;
} else if (a['in'] > b['in']) {
ret = 1;
} else if (a.out < b.out) {
ret = -1;
} else if (a.out > b.out) {
ret = 1;
} else if (a.value < b.value) {
ret = -1;
} else if (a.value > b.value) {
ret = 1;
}
return ret;
} }
function submitAnnotation(data) { function submitAnnotation(data) {
self.annotations = getAnnotations();
self.positions = getPositions();
updateWords('add'); updateWords('add');
self.editing = false; self.editing = false;
setTimelineState(); setTimelineState();
Ox.print('....', self.options.annotationsRange == 'position',
self.options.position < self.options['in'],
self.options.position > self.options.out)
if ( if (
self.options.annotationsRange == 'position' && ( self.options.annotationsRange == 'position'
&& (
self.options.position < self.options['in'] self.options.position < self.options['in']
|| self.options.position > self.options.out || self.options.position > self.options.out
) )
@ -1185,7 +1163,7 @@ Ox.VideoEditor = function(options, self) {
if (hasPressedEnter) { if (hasPressedEnter) {
that.triggerEvent('find', {find: self.options.find}); that.triggerEvent('find', {find: self.options.find});
if (self.results.length) { if (self.results.length) {
selectAnnotation(getNextResult(1)); selectAnnotation(getNextAnnotation('result', 1));
} else { } else {
self.$findInput.focusInput(true); self.$findInput.focusInput(true);
} }
@ -1235,7 +1213,9 @@ Ox.VideoEditor = function(options, self) {
} else { } else {
self.words[index].count++; self.words[index].count++;
} }
} else { } else if (index > -1) {
// index is -1 when removing an annotation by editing
// (which removes the words) and clearing its value
if (self.words[index].count == 1) { if (self.words[index].count == 1) {
self.words.splice(index, 1); self.words.splice(index, 1);
} else { } else {
@ -1276,7 +1256,7 @@ Ox.VideoEditor = function(options, self) {
that.updateAnnotation = function(id, annotation) { that.updateAnnotation = function(id, annotation) {
// called from editannotation callback // called from editannotation callback
self.options.selected = annotation.id; self.options.selected = annotation.id; // fixme: needed?
self.$annotationPanel.updateItem(id, annotation); self.$annotationPanel.updateItem(id, annotation);
} }

View file

@ -692,6 +692,10 @@ Ox.VideoPlayer = function(options, self) {
blur: function() { blur: function() {
self.inputHasFocus = false; self.inputHasFocus = false;
submitPositionInput(); submitPositionInput();
},
submit: function() {
self.inputHasFocus = false;
submitPositionInput();
} }
}) })
.appendTo(self['$controls' + titleCase].$element); .appendTo(self['$controls' + titleCase].$element);

View file

@ -362,6 +362,13 @@ Forms
background: -webkit-linear-gradient(top, rgb(160, 160, 160), rgb(192, 192, 192)); background: -webkit-linear-gradient(top, rgb(160, 160, 160), rgb(192, 192, 192));
} }
.OxThemeClassic .OxArrayEditable.OxArrayEditableTextarea .OxEditableElement {
border-top-color: rgb(208, 208, 208);
}
.OxThemeClassic .OxEditableElement.OxSelected {
background: rgb(208, 208, 208);
}
/* /*
================================================================================ ================================================================================
Images Images
@ -521,6 +528,13 @@ Maps
color: rgb(64, 64, 64); color: rgb(64, 64, 64);
} }
.OxThemeClassic .OxTypeIcon {
border-color: rgb(0, 0, 0);
}
.OxThemeClassic .OxListMap .OxWarning {
border-bottom: 2px dotted rgb(255, 64, 64);
}
/* /*
================================================================================ ================================================================================
Menus Menus

View file

@ -232,7 +232,6 @@ Forms
} }
*/ */
.OxThemeModern input.OxCheckbox, .OxThemeModern input.OxCheckbox,
.OxThemeModern input.OxInput, .OxThemeModern input.OxInput,
.OxThemeModern textarea, .OxThemeModern textarea,
@ -350,6 +349,9 @@ Forms
background: -webkit-linear-gradient(top, rgb(0, 0, 0), rgb(32, 32, 32) 10%, rgb(64, 64, 64)); background: -webkit-linear-gradient(top, rgb(0, 0, 0), rgb(32, 32, 32) 10%, rgb(64, 64, 64));
} }
.OxThemeModern .OxArrayEditable.OxArrayEditableTextarea .OxEditableElement {
border-top-color: rgb(48, 48, 48);
}
.OxThemeModern .OxEditableElement.OxSelected { .OxThemeModern .OxEditableElement.OxSelected {
background: rgb(48, 48, 48); background: rgb(48, 48, 48);
} }
@ -518,6 +520,12 @@ Maps
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
color: rgb(192, 192, 192); color: rgb(192, 192, 192);
} }
.OxThemeModern .OxTypeIcon {
border-color: rgb(255, 255, 255);
}
.OxThemeModern .OxListMap .OxWarning {
border-bottom: 2px dotted rgb(192, 0, 0);
}
/* /*
================================================================================ ================================================================================

View file

@ -9,9 +9,10 @@ Ox.formatArea <f> Formats a number of meters as square meters or kilometers
@*/ @*/
Ox.formatArea = function(num, dec) { Ox.formatArea = function(num, dec) {
dec = Ox.isUndefined(dec) ? 8 : dec;
var km = num >= 1000000; var km = num >= 1000000;
return Ox.formatNumber( return Ox.formatNumber(
(km ? num / 1000000 : num).toPrecision(8) (km ? num / 1000000 : num).toPrecision(dec)
) + ' ' + (km ? 'k' : '') + 'm\u00B2'; ) + ' ' + (km ? 'k' : '') + 'm\u00B2';
}; };

View file

@ -1,3 +1,4 @@
'use strict';
/*@ /*@
Ox.cache <f> Memoize a function Ox.cache <f> Memoize a function
<script> <script>
@ -26,4 +27,4 @@ Ox.cache = function(fn) {
return ret; return ret;
} }
return ret; return ret;
}; };