diff --git a/source/Ox.UI/js/Calendar/Ox.ListCalendar.js b/source/Ox.UI/js/Calendar/Ox.ListCalendar.js index 05e4f87b..328637b2 100644 --- a/source/Ox.UI/js/Calendar/Ox.ListCalendar.js +++ b/source/Ox.UI/js/Calendar/Ox.ListCalendar.js @@ -12,27 +12,72 @@ Ox.ListCalendar = function(options, self) { var that = Ox.Element({}, self) .defaults({ addEvent: null, - editPlace: null, + collapsible: false, + editEvent: null, events: [], + hasMatches: false, height: 256, + mode: 'add', pageLength: 100, - removePlace: null, - selected: [], + removeEvent: null, + selected: '', showControls: false, sort: [{key: 'name', operator: '+'}], width: 256 }) .options(options || {}) - .addClass('OxListCalendar') .css({ width: self.options.width + 'px', height: self.options.height + 'px' }); + Ox.print('LCO', self.options) + self.durationCache = {}; + self.durationSize = { + 86400: 10, + 31622400: 12 + }; self.columns = [ { + format: function(value, data) { + var eventDuration = (Ox.parseDate(data.end) - Ox.parseDate(data.start)) / 1000, + iconSize = 8; + Ox.forEach(self.durationSize, function(size, duration) { + if (eventDuration >= duration) { + iconSize = size; + } else { + return false; + } + }); + return data.type + ? $('
') + .addClass('OxEvent Ox' + Ox.toTitleCase(data.type)) + .css({ + width: iconSize + 'px', + height: iconSize + 'px', + margin: [0, 0, 0, -3].map(function(v) { + return v + (14 - iconSize) / 2 + 'px'; + }).join(' '), + borderRadius: '2px' + }) + : ''; + }, + id: 'type', + operator: '+', + title: 'Type', + titleImage: 'icon', + visible: true, + width: 16 + }, + { + format: function(value, data) { + Ox.print('format', value, data) + return data.type + ? value + : $('').addClass('OxWarning').html(value); + }, id: 'name', operator: '+', removable: false, @@ -51,16 +96,6 @@ Ox.ListCalendar = function(options, self) { visible: true, width: 144 }, - { - format: function(value) { - return Ox.toTitleCase(value); - }, - id: 'type', - operator: '+', - title: 'Type', - visible: true, - width: 64 - }, { id: 'start', map: function(value) { @@ -128,17 +163,18 @@ Ox.ListCalendar = function(options, self) { title: 'Date Modified', visible: false, width: 128, - }, - { - align: 'right', - id: 'matches', - operator: '-', - title: 'Matches', - visible: false, - width: 64, } ]; + self.options.hasMatches && self.columns.push({ + align: 'right', + id: 'matches', + operator: '-', + title: 'Matches', + visible: true, + width: 64, + }); + self.$listToolbar = Ox.Bar({ size: 24 }); @@ -176,11 +212,6 @@ Ox.ListCalendar = function(options, self) { ] }) .css({float: 'right', margin: '4px'}) - .bindEvent({ - change: function(data) { - - } - }) .appendTo(self.$listToolbar); self.$list = Ox.TextList({ @@ -191,8 +222,12 @@ Ox.ListCalendar = function(options, self) { // self.$list.options({items: self.options.events}) still // registers as a change items: Ox.clone(self.options.events, true), + keys: ['matches'], + max: 1, + min: 0, pageLength: self.options.pageLength, scrollbarVisible: true, + selected: self.options.selected ? [self.options.selected] : [], sort: self.options.sort }) .bindEvent({ @@ -208,7 +243,7 @@ Ox.ListCalendar = function(options, self) { self.$calendar.zoom(-1); }, key_shift_0: function() { - self.$calendar.zoomToPlace(); + self.$calendar.zoomToEvent(); }, load: function() { that.triggerEvent('loadlist'); @@ -231,25 +266,25 @@ Ox.ListCalendar = function(options, self) { .appendTo(self.$listStatusbar); self.$calendar = Ox.Calendar({ - date: new Date(0), - //events: Ox.clone(self.options.events, true), - events: self.options.events.filter(function(event) { - return !!event.start; - }), - height: self.options.height, - showControls: self.options.showControls, - showToolbar: true, - showZoombar: true, - width: self.options.width - 514, - zoom: 4 - }) - .bindEvent({ - resize: function(data) { - // triggered by SplitPanel - self.$calendar.resizeCalendar(); - }, - select: selectEvent - }); + date: new Date(0), + //events: Ox.clone(self.options.events, true), + events: self.options.events.filter(function(event) { + return !!event.type; + }), + height: self.options.height, + showControls: self.options.showControls, + showToolbar: true, + showZoombar: true, + width: self.options.width - 514, + zoom: 4 + }) + .bindEvent({ + resize: function(data) { + // triggered by SplitPanel + self.$calendar.resizeCalendar(); + }, + select: selectEvent + }); self.$eventTitlebar = Ox.Bar({ size: 24 @@ -279,11 +314,15 @@ Ox.ListCalendar = function(options, self) { .css({float: 'left', margin: '4px 4px 4px 0'}) .bindEvent({ click: function() { - self.$calendar.options({selected: null}); + self.$list.options({selected: []}); + // FIXME: list doesn't fire select event + selectItem({ids: []}); } }) .appendTo(self.$eventTitle); + self.$eventData = Ox.Element(); + self.$eventForm = Ox.Form({ items: [ self.$nameInput = Ox.Input({ @@ -345,8 +384,11 @@ Ox.ListCalendar = function(options, self) { Ox.forEach(self.options.events, function(event) { Ox.forEach(values, function(value) { if ( - event.name == data.data.value - || event.alternativeNames.indexOf(data.data.value) > -1 + event.type + && ( + event.name == data.data.value + || event.alternativeNames.indexOf(data.data.value) > -1 + ) ) { exists = value; return false; @@ -376,7 +418,21 @@ Ox.ListCalendar = function(options, self) { editEvent('end', data.data.value); } } - }); + }) + .appendTo(self.$eventData); + + if (self.options.hasMatches) { + self.$matchesInput = Ox.Input({ + disabled: true, + id: 'matches', + label: 'Matches', + labelWidth: 64, + type: 'int', + width: 240 + }) + .css({margin: '8px'}) + .appendTo(self.$eventData); + } self.$eventStatusbar = Ox.Bar({ size: 24 @@ -384,9 +440,9 @@ Ox.ListCalendar = function(options, self) { self.$newEventButton = Ox.Button({ title: 'New Event', - width: 96 + width: 70 }) - .css({float: 'left', margin: '4px 2px 4px 4px'}) + .css({float: 'left', margin: '4px'}) .bindEvent({ click: addEvent }) @@ -394,76 +450,101 @@ Ox.ListCalendar = function(options, self) { self.$removeEventButton = Ox.Button({ title: 'Remove Event', - width: 96 + width: 90 }) - .css({float: 'right', margin: '4px 4px 4px 2px'}) + .css({float: 'right', margin: '4px'}) .bindEvent({ click: removeEvent }) .hide() .appendTo(self.$eventStatusbar); - that.$element = Ox.SplitPanel({ - elements: [ - { - collapsible: true, - element: Ox.SplitPanel({ - elements: [ - { - element: self.$listToolbar, - size: 24 - }, - { - element: self.$list - }, - { - element: self.$listStatusbar, - size: 16 - } - ], - orientation: 'vertical' - }), - resizable: true, - resize: [256, 384, 512], - size: 256 - }, - { - element: self.$calendar, - }, - { - collapsible: true, - element: Ox.SplitPanel({ - elements: [ - { - element: self.$eventTitlebar, - size: 24 - }, - { - element: self.$eventForm - }, - { - element: self.$eventStatusbar, - size: 24 - } - ], - orientation: 'vertical' - }) - .bindEvent({ - resize: function(data) { - self.$placeTitleName.options({width: data.size - 48}); - // fixme: pass width through form - self.$placeFormItems.forEach(function($item) { - $item.options({width: data.size - 16}); - }); + if (self.options.mode == 'define') { + self.$defineEventButton = Ox.Button({ + title: 'Define Event', + width: 80 + }) + .css({float: 'right', margin: '4px 0 4px 0'}) + .bindEvent({ + click: function() { + if (this.options('title') == 'Define Event') { + defineEvent(); + } else { + clearEvent(); } - }), - resizable: true, - resize: [204, 256, 384], - size: 256 - } - ], - orientation: 'horizontal' - }); + } + }) + .hide() + .appendTo(self.$eventStatusbar); + } + + that.$element.replaceWith( + that.$element = Ox.SplitPanel({ + elements: [ + { + collapsible: self.options.collapsible, + element: Ox.SplitPanel({ + elements: [ + { + element: self.$listToolbar, + size: 24 + }, + { + element: self.$list + }, + { + element: self.$listStatusbar, + size: 16 + } + ], + orientation: 'vertical' + }), + resizable: true, + resize: [256, 384, 512], + size: 256 + }, + { + element: self.$calendar, + }, + { + collapsible: self.options.collapsible, + element: Ox.SplitPanel({ + elements: [ + { + element: self.$eventTitlebar, + size: 24 + }, + { + element: self.$eventData + }, + { + element: self.$eventStatusbar, + size: 24 + } + ], + orientation: 'vertical' + }) + .bindEvent({ + resize: function(data) { + self.$eventTitleName.options({width: data.size - 48}); + // fixme: pass width through form + /* + self.$eventFormItems.forEach(function($item) { + $item.options({width: data.size - 16}); + }); + */ + } + }), + resizable: true, + resize: [256, 384], + size: 256 + } + ], + orientation: 'horizontal' + }) + .addClass('OxListMap') + .$element + ); function addEvent() { Ox.Log('Calendar', 'ADD', self.$calendar.getBounds()) @@ -494,17 +575,53 @@ Ox.ListCalendar = function(options, self) { self.$nameInput.focusInput(true); } else { // FIXME - alert(result.status.text); + // alert(result.status.text); } }); } + function clearEvent() { + var event = Ox.getObjectById(self.options.events, self.options.selected), + values = { + id: self.options.selected, + alternativeNames: [], type: '', + start: '', end: '' + }; + self.$defineEventButton.options({disabled: true, title: 'Clear Event'}); + self.options.editEvent(values, function() { + Ox.forEach(values, function(value, key) { + self.$list.value(self.options.selected, key, value); + }); + self.$list.reloadList(); + self.$calendar.removeEvent(); + self.$eventForm.hide(); + self.$defineEventButton.options({disabled: false, title: 'Define Event'}); + }); + } + + function defineEvent() { + var bounds = self.$calendar.getBounds(), + middle = +self.$calendar.options('date'), + startTime = +new Date((+bounds.startTime + middle) / 2), + endTime = +new Date((+bounds.endTime + middle) / 2), + event = Ox.getObjectById(self.options.events, self.options.selected); + event.name = self.$list.value(self.options.selected, 'name'); + event.alternativeNames = []; + event.type = 'other'; + event.start = Ox.formatDate(startTime, '%Y-%m-%d %H:%M:%S', true); + event.end = Ox.formatDate(endTime, '%Y-%m-%d %H:%M:%S', true); + self.$list.options({items: Ox.clone(self.options.events, true)}); + self.$calendar.addEvent(event); + self.$defineEventButton.options({title: 'Clear Event'}); + } + function editEvent(key, value) { var id = self.selectedEvent, index = Ox.getIndexById(self.options.events, id), data = {id: id}; data[key] = value; self.options.editEvent(data, function(result) { + Ox.print('EDIT EVENT::', result.data) if (result.status.code == 200) { self.options.events[index][key] = value; self.$list.value(id, key, value); @@ -521,6 +638,11 @@ Ox.ListCalendar = function(options, self) { ) ); } + self.$list.value(id, 'matches', result.data.matches); + self.$matchesInput.value(result.data.matches); + self.options.mode == 'define' && self.$removeEventButton.options({ + disabled: !!result.data.matches + }); } else { // ... } @@ -566,39 +688,72 @@ Ox.ListCalendar = function(options, self) { self.$calendar.removeEvent(); selectEvent({}); } else { - alert(result.status.text); + // FIXME + // alert(result.status.text); } }); } function selectEvent(event) { - self.$list.options({ - selected: event.id ? [event.id] : [] - }); - if (event.id) { - var end = event - self.selectedEvent = event.id; - self.$eventName.options({title: event.name}); - self.$eventTitle.show(); - Ox.print('VALUES:', Ox.extend({}, event, { - end: event.current ? '' : event.end - })) - self.$eventForm.values(Ox.extend({}, event, { - end: event.current ? '' : event.end - })).show(); - self.$removeEventButton.show(); + // Select event on calendar + var isUndefined = !!self.options.selected + && !self.$list.value(self.options.selected, 'type'); + self.selectedEvent = event.id || ''; + if (!self.selectedPlace && isUndefined) { + // deselect triggered by selecting an undefined item, + // so do nothing } else { - self.selectedEvent = null; - self.$eventTitle.hide(); - self.$eventForm.hide(); - self.$removeEventButton.hide(); + self.options.selected = self.selectedEvent; + self.$list.options({ + selected: self.options.selected ? [self.options.selected] : [] + }); + selectItem({ids: self.$list.options('selected')}); } } function selectItem(data) { - var id = data.ids.length ? data.ids[0] : null; - self.$calendar.options({selected: id}); - id && self.$calendar.panToEvent(); + // Select item in list + Ox.print('selectItem', data); + var event, isUndefined, selectedEvent; + self.options.selected = data.ids.length ? data.ids[0] : ''; + event = self.options.selected + ? self.$list.value(self.options.selected) : {}; + isUndefined = !!self.options.selected + && !self.$list.value(self.options.selected, 'type'); + selectedEvent = self.options.selected && !isUndefined + ? self.options.selected : ''; + self.$calendar.options({selected: selectedEvent}); + selectedEvent && self.$calendar.panToEvent(); + Ox.print('EVENT', event, self.options.hasMatches) + if (self.options.selected) { + self.$eventName.options({title: event.name || ''}); + self.$eventTitle.show(); + if (!isUndefined) { + self.$eventForm.values(Ox.extend({}, event, { + end: event.current ? '' : event.end + })).show(); + } else { + self.$eventForm.hide(); + } + self.options.hasMatches && self.$matchesInput.value(event.matches || 0).show(); + self.options.mode == 'define' && self.$defineEventButton.options({ + title: isUndefined ? 'Define Event' : 'Clear Event' + }).show(); + self.$defineEventButton.options({ + disabled: !event.matches, + title: isUndefined ? 'Define Event' : 'Clear Event' + }).show(); + self.$removeEventButton.options({ + disabled: self.options.mode == 'define' && !!event.matches + }).show(); + } else { + self.$eventTitle.hide(); + self.$eventForm.hide(); + self.options.hasMatches && self.$matchesInput.hide(); + self.options.mode == 'define' && self.$defineEventButton.hide(); + self.$removeEventButton.hide(); + } + return; } function updateList(key, value) { diff --git a/source/Ox.UI/js/List/Ox.List.js b/source/Ox.UI/js/List/Ox.List.js index 035024c9..20b5ad88 100644 --- a/source/Ox.UI/js/List/Ox.List.js +++ b/source/Ox.UI/js/List/Ox.List.js @@ -1390,7 +1390,6 @@ Ox.List = function(options, self) { updateQuery(); } } else if (key == 'selected') { - //Ox.Log('List', 'setOption selected', value) previousSelected = self.selected; setSelected(value); // fixme: the following was added in order diff --git a/source/Ox.UI/js/List/Ox.TextList.js b/source/Ox.UI/js/List/Ox.TextList.js index 54a41fc0..78dd0a67 100644 --- a/source/Ox.UI/js/List/Ox.TextList.js +++ b/source/Ox.UI/js/List/Ox.TextList.js @@ -585,7 +585,7 @@ Ox.TextList = function(options, self) { } function getCell(id, key) { - Ox.Log('List', 'getCell', id, key) + Ox.print('List', 'getCell', id, key) var $item = getItem(id); key = key || ''; // fixme: what is this? return $($item.find('.OxCell.OxColumn' + Ox.toTitleCase(key))[0]); diff --git a/source/Ox.UI/js/Map/Ox.ListMap.js b/source/Ox.UI/js/Map/Ox.ListMap.js index c6c344e8..dc8257c0 100644 --- a/source/Ox.UI/js/Map/Ox.ListMap.js +++ b/source/Ox.UI/js/Map/Ox.ListMap.js @@ -23,9 +23,10 @@ Ox.ListMap = function(options, self) { var that = Ox.Element({}, self) .defaults({ addPlace: null, - editPlace: null, collapsible: false, + editPlace: null, getMatches: null, + hasMatches: false, height: 256, labels: false, mode: 'add', @@ -73,7 +74,7 @@ Ox.ListMap = function(options, self) { }, { format: function(value, data) { - return data.geoname + return data.type ? $('') .attr({ src: Ox.getFlagByGeoname(data.geoname, 16) @@ -143,7 +144,7 @@ Ox.ListMap = function(options, self) { format: function(value, data) { return data.type ? value - : $('').addClass('OxWarning').html(value) + : $('').addClass('OxWarning').html(value); }, id: 'name', operator: '+', @@ -264,17 +265,18 @@ Ox.ListMap = function(options, self) { title: 'Date Modified', visible: false, width: 128, - }, - { - align: 'right', - id: 'matches', - operator: '-', - title: 'Matches', - visible: false, - width: 64, } ]; + self.options.hasMatches && self.columns.push({ + align: 'right', + id: 'matches', + operator: '-', + title: 'Matches', + visible: true, + width: 64 + }); + self.$listToolbar = Ox.Bar({ size: 24 }); @@ -313,19 +315,14 @@ Ox.ListMap = function(options, self) { ] }) .css({float: 'right', margin: '4px'}) - .bindEvent({ - change: function(data) { - - } - }) .appendTo(self.$listToolbar); self.$list = Ox.TextList({ columns: self.columns, columnsRemovable: true, columnsVisible: true, - //items: Ox.clone(self.options.places), - items: self.options.places, + items: Ox.clone(self.options.places), + //items: self.options.places, // area needed for icon, geoname needed for flag keys: ['area', 'geoname', 'matches'], max: 1, @@ -367,47 +364,47 @@ Ox.ListMap = function(options, self) { .appendTo(self.$listStatusbar); self.$map = Ox.Map({ - clickable: true, - editable: true, - findPlaceholder: 'Find on Map', - height: self.options.height, - places: self.options.places, - selected: self.options.selected, - //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 - }, - */ - selectplace: selectPlace - }); + clickable: true, + editable: true, + findPlaceholder: 'Find on Map', + height: self.options.height, + places: self.options.places, + selected: self.options.selected, + //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 + }, + */ + selectplace: selectPlace + }); self.$placeTitlebar = Ox.Bar({ size: 24 @@ -457,157 +454,139 @@ Ox.ListMap = function(options, self) { .css({float: 'left', margin: '4px'}) .bindEvent({ click: function() { - self.$map.options({selected: null}); + self.$list.options({selected: []}); + // FIXME: list doesn't fire select event + selectItem({ids: []}); } }) .appendTo(self.$placeTitle); - self.$nameInput = Ox.Input({ - id: 'name', - label: 'Name', - labelWidth: 64, - width: 240 - }).bindEvent({ - change: function(data) { - var isResult = self.selectedPlace[0] == '_'; - !isResult && self.$list.value(self.selectedPlace, 'name', data.value); - if (!self.isAsync) { - Ox.getObjectById( - self.options.places, self.selectedPlace - ).name = data.value; - } else { - !isResult && editPlace(['name']); - } - self.$map.value(self.selectedPlace, 'name', data.value); - } - }); - - self.$alternativeNamesInput = Ox.ArrayInput({ - id: 'alternativeNames', - label: 'Alternative Names', - max: 10, - //sort: true, - values: [], - width: 240 - }).bindEvent({ - change: function(data) { - var isResult = self.selectedPlace[0] == '_'; - if (!self.isAsync) { - - } else { - !isResult && editPlace(['alternativeNames']) - } - self.$map.value(self.selectedPlace, 'alternativeNames', data.value); - } - }); - - self.$geonameInput = Ox.Input({ - id: 'geoname', - label: 'Geoname', - labelWidth: 64, - width: 240 - }).bindEvent({ - change: function(data) { - var geoname = data.value, - country = Ox.getCountryByGeoname(geoname), - countryCode = country ? country.code : '', - isResult = self.selectedPlace[0] == '_'; - Ox.print('CHANGE', geoname, country, countryCode, self.isAsync); - self.$placeFlag.attr({ - src: Ox.getFlagByGeoname(geoname, 16) - }); - self.$placeName.options({title: geoname}); - 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); - } - }); - - // fixme: form should have a change event - // fixme: it has one now, but inputs fire on blur - self.$placeFormItems = Ox.merge([ - self.$nameInput, - self.$alternativeNamesInput, - self.$geonameInput, - Ox.Input({ - id: 'countryCode' - }).hide(), - Ox.Select({ - id: 'type', - items: [ - {id: 'country', title: 'Country'}, - {id: 'region', title: 'Region'}, // administative (Kansas) or colloquial (Midwest) - {id: 'city', title: 'City'}, - {id: 'borough', title: 'Borough'}, - {id: 'street', title: 'Street'}, // streets, squares, bridges, tunnels, ... - {id: 'building', title: 'Building'}, // airports, stations, stadiums, military installations, ... - {id: 'feature', title: 'Feature'} // continents, islands, rivers, lakes, seas, oceans, mountains... - ], - label: 'Type', - labelWidth: 64, - width: 240 - }).bindEvent({ - change: function(data) { - var isResult = self.selectedPlace[0] == '_'; - if (!self.isAsync) { - // ... - } else { - !isResult && editPlace(['type']) - } - self.$map.value(self.selectedPlace, 'type', data.value); - } - }) - ], ['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({ - decimals: 8, - disabled: ['lat', 'lng'].indexOf(id) > -1, - id: id, - label: v, - labelWidth: 80, - min: -max, - max: max, - type: 'float', - width: 240 - }) - .bindEvent({ - blur: function(data) { - ///* - // fixme: if type is set, no change event fires - var isResult = self.selectedPlace[0] == '_'; - if (!self.isAsync) { - // ... - } else { - !isResult && editPlace([v]) - } - self.$map.value(self.selectedPlace, id, parseFloat(data.value)); - //*/ - } - }); - }), [ - self.$areaInput = Ox.Input({ - id: 'area', - type: 'float' - }).hide() - ]); + self.$placeData = Ox.Element(); self.$placeForm = Ox.Form({ - items: self.$placeFormItems, + items: Ox.merge([ + self.$nameInput = Ox.Input({ + id: 'name', + label: 'Name', + labelWidth: 64, + width: 240 + }), + self.$alternativeNamesInput = Ox.ArrayInput({ + id: 'alternativeNames', + label: 'Alternative Names', + max: 10, + //sort: true, + values: [], + width: 240 + }), + self.$geonameInput = Ox.Input({ + id: 'geoname', + label: 'Geoname', + labelWidth: 64, + width: 240 + }), + Ox.Input({ + id: 'countryCode' + }).hide(), + Ox.Select({ + id: 'type', + items: [ + {id: 'country', title: 'Country'}, + {id: 'region', title: 'Region'}, // administative (Kansas) or colloquial (Midwest) + {id: 'city', title: 'City'}, + {id: 'borough', title: 'Borough'}, + {id: 'street', title: 'Street'}, // streets, squares, bridges, tunnels, ... + {id: 'building', title: 'Building'}, // airports, stations, stadiums, military installations, ... + {id: 'feature', title: 'Feature'} // continents, islands, rivers, lakes, seas, oceans, mountains... + ], + label: 'Type', + labelWidth: 64, + 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({ + decimals: 8, + disabled: ['lat', 'lng'].indexOf(id) > -1, + id: id, + label: v, + labelWidth: 80, + min: -max, + max: max, + type: 'float', + width: 240 + }); + }), + [ + self.$areaInput = Ox.Input({ + id: 'area', + type: 'float' + }).hide() + ]), width: 240 }) .css({margin: '8px'}) - .hide(); + .hide() + .bindEvent({ + change: function(data) { + var isResult = self.selectedPlace[0] == '_'; + if (data.id == 'name') { + !isResult && self.$list.value(self.selectedPlace, 'name', data.data.value); + if (!self.isAsync) { + Ox.getObjectById( + self.options.places, self.selectedPlace + ).name = data.data.value; + } else { + !isResult && editPlace(['name']); + } + self.$map.value(self.selectedPlace, 'name', data.data.value); + } else if (data.id == 'alternativeNames') { + if (!self.isAsync) { + // ... + } else { + !isResult && editPlace(['alternativeNames']) + } + 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.$placeName.options({title: geoname}); + 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']) + } + self.$map.value(self.selectedPlace, 'type', data.data.value); + } else { // lat, lng, south, west, north, east + if (!self.isAsync) { + // ... + } else { + !isResult && editPlace([data.id]) + } + self.$map.value(self.selectedPlace, data.id, parseFloat(data.data.value)); + } + } + }) + .appendTo(self.$placeData); self.$areaKmInput = Ox.Input({ disabled: true, @@ -617,20 +596,22 @@ Ox.ListMap = function(options, self) { textAlign: 'right', width: 240 }) - .css({margin: '4px 0 4px 0'}) - .appendTo(self.$placeForm); + .css({margin: '8px 8px 0 8px'}) + .hide() + .appendTo(self.$placeData); - if (self.options.getMatches) { + if (self.options.hasMatches) { self.$matchesInput = Ox.Input({ - disabled: true, - id: 'matches', - label: 'Matches', - labelWidth: 80, - type: 'int', - width: 240 - }) - .css({margin: '8px 0 4px 0'}) - .appendTo(self.$placeForm); + disabled: true, + id: 'matches', + label: 'Matches', + labelWidth: 80, + type: 'int', + width: 240 + }) + .css({margin: '8px'}) + .hide() + .appendTo(self.$placeData); } self.$placeStatusbar = Ox.Bar({ @@ -685,16 +666,6 @@ Ox.ListMap = function(options, self) { .appendTo(self.$placeStatusbar); } - /* - self.$revertButton = Ox.Button({ - title: 'Revert', - width: 96 - }) - .css({float: 'right', margin: '4px 4px 4px 2px'}) - .hide() - .appendTo(self.$placeStatusbar); - */ - /* self.mapResize = [ Math.round(self.options.width * 0.25), @@ -757,7 +728,7 @@ Ox.ListMap = function(options, self) { size: 24 }, { - element: self.$placeForm + element: self.$placeData }, { element: self.$placeStatusbar, @@ -803,9 +774,7 @@ Ox.ListMap = function(options, self) { self.$map.addPlace(place); self.$addPlaceButton.options({title: 'Remove Place'}); //setStatus(); - } - //that.triggerEvent('addplace', {place: place}); - if (self.isAsync) { + } else { self.$addPlaceButton.options({disabled: true, title: 'Adding...'}); self.options.addPlace(place, function(result) { if (result.status.code == 200) { @@ -813,17 +782,22 @@ Ox.ListMap = function(options, self) { self.selectedPlace = place.id; self.$list.reloadList().options({selected: [place.id]}); self.$map.addPlace(place); - self.$addPlaceButton.options({disabled: false, title: 'Remove Place'}); - } else { - if (result.data.names) { - if (result.data.names.indexOf(self.$nameInput.value()) > -1) { - self.$nameInput.addClass('OxError'); - } - self.$alternativeNamesInput.setErrors(result.data.names); - } - if (result.data.geoname) { - self.$geonameInput.addClass('OxError'); + self.options.hasMatches && self.$matchesInput.value( + result.data.matches + ).show(); + self.options.mode == 'define' && self.$definePlaceButton.options({ + disabled: !result.data.matches, + title: 'Clear Place' + }).show(); + self.$addPlaceButton.options({ + disabled: false, + title: 'Remove Place' + }).show(); + } else if (result.status.code == 409) { + if (result.data.names.indexOf(self.$nameInput.value()) > -1) { + self.$nameInput.addClass('OxError'); } + self.$alternativeNamesInput.setErrors(result.data.names); self.$addPlaceButton.options({disabled: false, title: 'Add Place'}); } }); @@ -840,17 +814,18 @@ Ox.ListMap = function(options, self) { self.$definePlaceButton.options({disabled: true, title: 'Clearing...'}); self.options.editPlace(values, function() { self.$list.reloadList(); - self.$map.removePlace(); + self.$map.removePlace().options({selected: ''}); self.$findPlaceButton.show(); self.$placeFlag.hide(); self.$placeForm.hide(); + self.$areaKmInput.hide(); self.$definePlaceButton.options({disabled: false, title: 'Define Place'}) }); } function definePlace() { self.$map.newPlace(); // this will call selectPlace, then editPlace - self.$definePlaceButton.options({title: 'Clear Place'}) + self.$definePlaceButton.options({title: 'Clear Place'}); } function editPlace(keys) { @@ -859,27 +834,56 @@ Ox.ListMap = function(options, self) { return keys.indexOf(key) > -1; }); values.id = self.selectedPlace; - self.options.editPlace(values, function() { - if (keys.indexOf(self.$list.options('sort')[0].key) > -1) { - self.$list.reloadList(); + self.options.editPlace(values, function(result) { + Ox.print('EDIT PLACE::', result) + 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, + title: 'Clear Place' + }); + self.$addPlaceButton.options({ + disabled: !!result.data.matches + }); + } } else { - Ox.forEach(values, function(value, key) { - if (key != 'id') { - self.$list.value(values.id, key, value); - self.$map.value(values.id, key, value); - } - }); + if (result.data.names.indexOf(self.$nameInput.value()) > -1) { + self.$nameInput.addClass('OxError'); + } + self.$alternativeNamesInput.setErrors(result.data.names); } }); - if (keys.indexOf('name') > -1 || keys.indexOf('alternativeNames') > -1) { - updateMatches(); - } } function findPlace() { - self.$map.options({ - find: self.$list.value(self.selectedPlace).name - }); + self.$map + //.options({find: ''}) + .options({find: self.$list.value(self.options.selected, 'name')}); } function initList(data) { @@ -918,98 +922,125 @@ Ox.ListMap = function(options, self) { self.$addPlaceButton.options({disabled: true, title: 'Removing...'}) self.options.removePlace({id: self.selectedPlace}, function() { self.$list.options({selected: []}).reloadList(true); + self.options.hasMatches && self.$matchesInput.hide(); self.options.mode == 'define' && self.$definePlaceButton.options({ disabled: true }); - self.$addPlaceButton.options({disabled: false, title: 'Add Place'}) + self.$addPlaceButton.options({disabled: false, title: 'Add Place'}); }); } self.$map.removePlace(); that.triggerEvent('removeplace', {id: self.selectedPlace}); } - function selectItem(data) { + function selectItem(data, place) { // Select item in list + Ox.print('selectItem', data, place); var isUndefined, selectedPlace; self.options.selected = data.ids.length ? data.ids[0] : ''; - isUndefined = !!self.options.selected - && !self.$list.value(self.options.selected, 'type'); + place = place || ( + self.options.selected + ? self.$list.value(self.options.selected) : {} + ); + isUndefined = !!self.options.selected && !place.type; selectedPlace = self.options.selected && !isUndefined - ? self.options.selected : null; + ? self.options.selected : ''; 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') - }); + 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(); - self.$definePlaceButton.options({ - title: 'Define Place' + if (!isUndefined) { + self.$placeForm.values(place).show(); + self.$areaKmInput.value(Ox.formatArea(place.area)).show(); + } else { + self.$placeForm.hide(); + self.$areaKmInput.hide(); + } + 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({ - disabled: self.$list.value(self.options.selected, 'matches') > 0, + disabled: self.options.mode == 'define' && !!place.matches, title: 'Remove Place' }).show(); + } else { + self.$placeTitle.hide(); + self.$placeForm.hide(); + self.$areaKmInput.hide(); + self.options.hasMatches && self.$matchesInput.hide(); + self.options.mode == 'define' && self.$definePlaceButton.hide(); + self.$addPlaceButton.hide(); } } function selectPlace(place) { // Select place on map Ox.print('selectPlace', place) - var isResult, isUndefined; - self.selectedPlace = place.id || null; - isResult = !!place.id && place.id[0] == '_'; - isUndefined = !!self.options.selected - && !self.$list.value(self.options.selected, 'type'); - Ox.print('isResult', isResult, 'isUndefined', isUndefined, self.options.selected) - if (!(isUndefined && !place.id)) { - // if isUndefined && !place.id, then we're handling the - // map deselect, which we don't want to pass to the list - self.$list.options({ - selected: place.id && !isResult ? [place.id] : [] - }); - } - if (place.id) { - if (isResult && isUndefined) { - self.selectedPlace = self.options.selected; - place.id = self.options.selected; - place.name = self.$list.value(self.options.selected, 'name'); - Ox.print('PLACE::::::', place) - } - self.options.mode == 'define' && self.$findPlaceButton.hide(); + var isResult = !!place.id && place.id[0] == '_', + isUndefined = !!self.options.selected + && !self.$list.value(self.options.selected, 'type'), + names; + self.selectedPlace = place.id || ''; + if (isResult && isUndefined) { + // 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.$placeForm.values(place).show(); + self.$areaKmInput.value(Ox.formatArea(place.area)).show(); + editPlace([ + 'geoname', 'type', + 'lat', 'lng', + 'south', 'west', 'north', 'east', 'area' + ]); + } else if (self.selectedPlace && isResult) { + // select result place + self.$list.options({selected: []}); self.$placeFlag.attr({ src: Ox.getFlagByGeoname(place.geoname || '', 16) }).show(); self.$placeName.options({title: place.name || ''}); self.$placeTitle.show(); self.$placeForm.values(place).show(); - self.$areaKmInput.value(Ox.formatArea(place.area)); - self.$matchesInput.value(place.matches); - //updateMatches(); - self.options.mode == 'define' && self.$definePlaceButton.options({ - title: isUndefined && !isResult ? 'Define Place' : 'Clear Place' - }).show(); - self.$addPlaceButton.options({ - disabled: self.options.mode == 'define' && place.matches > 0, - title: isResult ? 'Add Place' : 'Remove Place' - }).show(); - if (isResult && isUndefined) { - self.$map.addPlace(place); - self.$addPlaceButton.options({title: 'Remove Place'}); - editPlace([ - 'geoname', 'type', - 'lat', 'lng', - 'south', 'west', 'north', 'east', 'area' - ]); + self.$areaKmInput.value(Ox.formatArea(place.area)).show(); + if (self.options.hasMatches) { + self.$matchesInput.value('').show(); + names = Ox.filter(Ox.merge([place.name], place.alternativeNames), function(name) { + return name !== ''; + }); + self.options.getMatches(names, function(matches) { + self.$matchesInput.value(matches); + }); } - } else { + self.options.mode == 'define' && self.$definePlaceButton.hide(); + self.$addPlaceButton.options({disabled: false, title: 'Add Place'}).show(); + } else if (!self.selectedPlace && !self.options.selected) { + // deselect result place + self.$placeFlag.hide(); self.$placeTitle.hide(); self.$placeForm.hide(); - self.options.mode == 'define' && self.$definePlaceButton.hide(); - self.$addPlaceButton.hide(); + self.$areaKmInput.hide(); + 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); } } @@ -1022,7 +1053,6 @@ Ox.ListMap = function(options, self) { list == 'names' && !self.namesLoaded ? load() : toggle(); function load() { self.options.names(function(data) { - Ox.print('DATA IS', data); self.$namesList.options({items: data}); self.namesLoaded = true; toggle(); @@ -1054,24 +1084,6 @@ Ox.ListMap = function(options, self) { }); } - function updateMatches() { - var names, place; - if (self.options.getMatches) { - place = self.$placeForm.values(); - names = Ox.filter(Ox.merge([place.name], place.alternativeNames), function(name) { - return name !== ''; - }); - if (names.length) { - self.$matchesInput.value(''); - self.options.getMatches(names, function(matches) { - self.$matchesInput.value(Ox.formatNumber(matches)); - }); - } else { - self.$matchesInput.value(0); - } - } - } - /*@ setOption setOption @*/ diff --git a/source/Ox.UI/js/Map/Ox.Map.js b/source/Ox.UI/js/Map/Ox.Map.js index a65ec14e..fff41a80 100644 --- a/source/Ox.UI/js/Map/Ox.Map.js +++ b/source/Ox.UI/js/Map/Ox.Map.js @@ -536,6 +536,7 @@ Ox.Map = function(options, self) { self.options.selected = place.id; place.countryCode = country ? country.code : ''; Ox.Log('Map', 'addP2P', data, place); + setPlaceControls(place); place.marker.update(); self.places.push(place); self.resultPlace = null; @@ -1204,7 +1205,9 @@ Ox.Map = function(options, self) { src: Ox.getFlagByGeoname(place.geoname, 16) }) ).show(); - self.$placeControls.name.options({title: place.name}) + self.$placeControls.name.options({ + title: place.name ||'Unnamed' + }); !isVisible && $placeControls.show().animate({opacity: 1}, 250); } else { isVisible && $placeControls.animate({opacity: 0}, 250, function() { @@ -1272,7 +1275,7 @@ Ox.Map = function(options, self) { function submitFind(data) { self.options.find = data.value; if (data.value === '') { - if (self.options.selected[0] == '_') { + if (self.options.selected && self.options.selected[0] == '_') { selectPlace(null); } } else { @@ -1542,6 +1545,17 @@ Ox.Map = function(options, self) { that.value = function(id, key, value) { // fixme: should be like the corresponding List/TextList/etc value function Ox.print('Map', 'Map.value', id, key, value) + if (id == self.options.selected) { + if (key == 'name') { + self.$placeControls.name.options({title: value}); + } else if (key == 'geoname') { + self.$placeControls.flag.empty().append( + $('').attr({ + src: Ox.getFlagByGeoname(value, 16) + }) + ); + } + } getPlaceById(id).options(key, value); } diff --git a/source/Ox.UI/js/Map/Ox.MapMarker.js b/source/Ox.UI/js/Map/Ox.MapMarker.js index dd811bcc..d14633a5 100644 --- a/source/Ox.UI/js/Map/Ox.MapMarker.js +++ b/source/Ox.UI/js/Map/Ox.MapMarker.js @@ -245,7 +245,7 @@ Ox.MapMarker = function(options) { + Ox.getFlagByGeoname(that.place.geoname, 16) + '" style="float: left; margin: 1px 0 1px -1px; border-radius: 4px"/>' + '
' - + that.place.name + '
' + + (that.place.name || 'Unnamed') + '
' }) .addClass('OxMapMarkerTooltip'); } diff --git a/source/Ox.UI/themes/classic/css/classic.css b/source/Ox.UI/themes/classic/css/classic.css index 20e368b8..f16ef3ae 100644 --- a/source/Ox.UI/themes/classic/css/classic.css +++ b/source/Ox.UI/themes/classic/css/classic.css @@ -13,6 +13,9 @@ body.OxThemeClassic { .OxThemeClassic .OxBright { color: rgb(0, 0, 0); } +.OxThemeClassic .OxLight { + color: rgb(128, 128, 128); +} /* @@ -140,22 +143,22 @@ Calendar inset 0 0 1px rgb(0, 0, 0), inset 0 0 1px rgb(0, 0, 0); } -.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxDate { +.OxThemeClassic .OxEvent.OxDate { background: -moz-linear-gradient(top, rgba(128, 128, 255, 0.9), rgba(96, 96, 224, 0.9)); background: -o-linear-gradient(top, rgba(128, 128, 255, 0.9), rgba(96, 96, 224, 0.9)); background: -webkit-linear-gradient(top, rgba(128, 128, 255, 0.9), rgba(96, 96, 224, 0.9)); } -.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxPlace { +.OxThemeClassic .OxEvent.OxPlace { background: -moz-linear-gradient(top, rgba(0, 192, 96, 0.9), rgba(0, 160, 64, 0.9)); background: -o-linear-gradient(top, rgba(0, 192, 96, 0.9), rgba(0, 160, 64, 0.9)); background: -webkit-linear-gradient(top, rgba(0, 192, 96, 0.9), rgba(0, 160, 64, 0.9)); } -.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxPerson { +.OxThemeClassic .OxEvent.OxPerson { background: -moz-linear-gradient(top, rgba(255, 128, 0, 0.9), rgba(224, 96, 0, 0.9)); background: -o-linear-gradient(top, rgba(255, 128, 0, 0.9), rgba(224, 96, 0, 0.9)); background: -webkit-linear-gradient(top, rgba(255, 128, 0, 0.9), rgba(224, 96, 0, 0.9)); } -.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxOther { +.OxThemeClassic .OxEvent.OxOther { background: -moz-linear-gradient(top, rgba(255, 128, 128, 0.9), rgba(224, 96, 96, 0.9)); background: -o-linear-gradient(top, rgba(255, 128, 128, 0.9), rgba(224, 96, 96, 0.9)); background: -webkit-linear-gradient(top, rgba(255, 64, 64, 0.9), rgba(224, 32, 32, 0.9)); @@ -177,6 +180,10 @@ Calendar color: rgb(64, 64, 64); } +.OxThemeClassic .OxListCalendar .OxWarning { + border-bottom: 2px dotted rgb(255, 64, 64); +} + /* ================================================================================ Dialog diff --git a/source/Ox.UI/themes/modern/css/modern.css b/source/Ox.UI/themes/modern/css/modern.css index 11cf0620..08c7919f 100644 --- a/source/Ox.UI/themes/modern/css/modern.css +++ b/source/Ox.UI/themes/modern/css/modern.css @@ -18,6 +18,9 @@ body.OxThemeModern { .OxThemeModern .OxBright { color: rgb(255, 255, 255); } +.OxThemeModern .OxLight { + color: rgb(128, 128, 128); +} /* ================================================================================ @@ -139,22 +142,22 @@ Calendar inset 0 0 1px rgb(255, 255, 255), inset 0 0 1px rgb(255, 255, 255); } -.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxDate { +.OxThemeModern .OxEvent.OxDate { background: -moz-linear-gradient(top, rgba(96, 96, 192, 0.9), rgba(64, 64, 160, 0.9)); background: -o-linear-gradient(top, rgba(96, 96, 192, 0.9), rgba(64, 64, 160, 0.9)); background: -webkit-linear-gradient(top, rgba(96, 96, 255, 0.9), rgba(64, 64, 224, 0.9)); } -.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxPlace { +.OxThemeModern .OxEvent.OxPlace { background: -moz-linear-gradient(top, rgba(0, 128, 96, 0.9), rgba(0, 96, 64, 0.9)); background: -o-linear-gradient(top, rgba(0, 128, 96, 0.9), rgba(0, 96, 64, 0.9)); background: -webkit-linear-gradient(top, rgba(0, 128, 96, 0.9), rgba(0, 96, 64, 0.9)); } -.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxPerson { +.OxThemeModern .OxEvent.OxPerson { background: -moz-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 64, 0, 0.9)); background: -o-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 64, 0, 0.9)); background: -webkit-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 64, 0, 0.9)); } -.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxOther { +.OxThemeModern .OxEvent.OxOther { background: -moz-linear-gradient(top, rgba(192, 32, 32, 0.9), rgba(160, 0, 0, 0.9)); background: -o-linear-gradient(top, rgba(192, 32, 32, 0.9), rgba(160, 0, 0, 0.9)); background: -webkit-linear-gradient(top, rgba(192, 32, 32, 0.9), rgba(160, 0, 0, 0.9)); @@ -176,6 +179,10 @@ Calendar color: rgb(192, 192, 192); } +.OxThemeModern .OxListCalendar .OxWarning { + border-bottom: 2px dotted rgb(192, 0, 0); +} + /* ================================================================================ Dialog