diff --git a/build/Ox.UI/themes/classic/css/classic.css b/build/Ox.UI/themes/classic/css/classic.css index 42761923..8fdc9a49 100644 --- a/build/Ox.UI/themes/classic/css/classic.css +++ b/build/Ox.UI/themes/classic/css/classic.css @@ -111,13 +111,19 @@ Calendar .OxThemeClassic .OxCalendar .OxLine > .OxEvent { color: rgb(0, 0, 0); } +.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxSelected { + box-shadow: inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0); +} .OxThemeClassic .OxCalendar .OxOverlay div:nth-child(even) { - border-top: 1px solid rgba(0, 0, 0, 0.5); - border-bottom: 1px solid rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.25); + box-shadow: inset 0 0 2px rgb(0, 0, 0); } .OxThemeClassic .OxCalendar .OxOverlay div:nth-child(odd) { - background-color: rgba(255, 255, 255, 0.5); + background-color: rgba(255, 255, 255, 0.25); } /* diff --git a/build/Ox.UI/themes/modern/css/modern.css b/build/Ox.UI/themes/modern/css/modern.css index 3e4f3750..6bcd4784 100644 --- a/build/Ox.UI/themes/modern/css/modern.css +++ b/build/Ox.UI/themes/modern/css/modern.css @@ -110,13 +110,19 @@ Calendar .OxThemeModern .OxCalendar .OxLine > .OxEvent { color: rgb(255, 255, 255); } +.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxSelected { + box-shadow: inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255); +} .OxThemeModern .OxCalendar .OxOverlay div:nth-child(even) { - border-top: 1px solid rgba(255, 255, 255, 0.5); - border-bottom: 1px solid rgba(255, 255, 255, 0.5); + background-color: rgba(255, 255, 255, 0.25); + box-shadow: inset 0 0 2px rgb(255, 255, 255); } .OxThemeModern .OxCalendar .OxOverlay div:nth-child(odd) { - background-color: rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.25); } diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 9efcb18b..81003973 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -212,6 +212,7 @@ Calendar white-space: nowrap; } .OxCalendar .OxLine > .OxEvent { + //box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.5); border-radius: 4px; } .OxCalendar .OxLine > .OxEvent.OxCurrent { @@ -219,30 +220,24 @@ Calendar border-bottom-right-radius: 0; } .OxCalendar .OxLine > .OxEvent.OxDate { - background: -moz-linear-gradient(top, rgba(192, 0, 0, 0.9), rgba(160, 0, 0, 0.9)); - background: -o-linear-gradient(top, rgba(192, 0, 0, 0.9), rgba(160, 0, 0, 0.9)); - background: -webkit-linear-gradient(top, rgba(192, 0, 0, 0.9), rgba(160, 0, 0, 0.9)); + 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)); } .OxCalendar .OxLine > .OxEvent.OxPlace { - background: -moz-linear-gradient(top, rgba(255, 192, 0, 0.9), rgba(224, 160, 0, 0.9)); - background: -o-linear-gradient(top, rgba(255, 192, 0, 0.9), rgba(224, 160, 0, 0.9)); - background: -webkit-linear-gradient(top, rgba(255, 192, 0, 0.9), rgba(224, 160, 0, 0.9)); + 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)); } .OxCalendar .OxLine > .OxEvent.OxPerson { - background: -moz-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 80, 0, 0.9)); - background: -o-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 80, 0, 0.9)); - background: -webkit-linear-gradient(top, rgba(255, 96, 0, 0.9), rgba(224, 80, 0, 0.9)); + 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)); } .OxCalendar .OxLine > .OxEvent.OxOther { - background: -moz-linear-gradient(top, rgba(255, 0, 0, 0.9), rgba(224, 0, 0, 0.9)); - background: -o-linear-gradient(top, rgba(255, 0, 0, 0.9), rgba(224, 0, 0, 0.9)); - background: -webkit-linear-gradient(top, rgba(255, 0, 0, 0.9), rgba(224, 0, 0, 0.9)); -} - -.OxCalendar .OxLine > .OxEvent.OxSelected { - 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)); + 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)); } .OxCalendar .OxTimeline { @@ -268,7 +263,7 @@ Calendar cursor: ew-resize; } .OxCalendar .OxOverlay div:nth-child(even) { - height: 14px; + border-radius: 4px; } .OxCalendar .OxRange .OxArrow { diff --git a/source/Ox.UI/js/Calendar/Ox.Calendar.js b/source/Ox.UI/js/Calendar/Ox.Calendar.js index b1dd7ab1..8a61f1cf 100644 --- a/source/Ox.UI/js/Calendar/Ox.Calendar.js +++ b/source/Ox.UI/js/Calendar/Ox.Calendar.js @@ -46,9 +46,6 @@ Ox.Calendar = function(options, self) { //height: self.options.height + 'px' }) .bindEvent({ - anyclick: function(e) { - !$(e.target).is('.OxInput') && that.gainFocus(); - }, key_0: function() { panToSelected(); }, @@ -81,6 +78,9 @@ Ox.Calendar = function(options, self) { }, key_up: function() { scrollBy(-1); + }, + mousedown: function(e) { + !$(e.target).is('.OxInput') && that.gainFocus(); } }); @@ -423,7 +423,7 @@ Ox.Calendar = function(options, self) { } else { if (self.options.zoom < self.maxZoom) { self.options.date = new Date( - (+self.options.date + +getMouseDate(e)) / 2 + (+self.options.date + +getMouseDate(data)) / 2 ); self.options.zoom++; } @@ -583,10 +583,11 @@ Ox.Calendar = function(options, self) { event.id = Ox.isUndefined(event.id) ? Ox.uid() : event.id; event.startTime = Ox.parseDate(event.start, true); event.endTime = Ox.parseDate(event.end, true); + event.durationTime = event.endTime - event.startTime; event.rangeText = Ox.formatDateRange(event.start, event.end, true); event.durationText = Ox.formatDateRangeDuration(event.start, event.end, true); if (event.current) { - event.rangeText = event.rangeText.split(' - ').shift() + ' - ...'; + event.rangeText = event.rangeText.split(' - ').shift() + ' - now'; } return event; } @@ -633,16 +634,26 @@ Ox.Calendar = function(options, self) { return $element; } + function getEventLine(id) { + var line = -1; + Ox.forEach(self.lineEvents, function(events, line_) { + if (Ox.getPositionById(events, id) > -1) { + line = line_; + return false; + } + }); + return line; + } + function getLines() { self.lineEvents = []; self.$content.find('.OxLine').remove(); self.options.events.filter(function(event) { // filter out events with types not shown - // and events outside the visible area <-- commented out to keep layout from changing - return self.options.showTypes.indexOf(event.type) > -1 - /*&& overlaps(event, calendarEvent)*/; + return self.options.showTypes.indexOf(event.type) > -1; }).sort(function(a, b) { - // sort events (dates first, people last, longer before shorter) + // sort events (dates first, people last, longer before shorter, + // earlier before later, otherwise alphabetically by name) if (a.type == 'date' && b.type != 'date') { return -1; } else if (a.type != 'date' && b.type == 'date') { @@ -651,10 +662,12 @@ Ox.Calendar = function(options, self) { return 1; } else if (a.type != 'person' && b.type == 'person') { return -1; - } else if ((b.endTime - b.startTime) != (a.endTime - a.startTime)) { - return (b.endTime - b.startTime) - (a.endTime - a.startTime); - } else /*if (a.startTime < b.startTime || a.startTime > b.startTime)*/ { + } else if (a.durationTime != b.durationTime) { + return b.durationTime - a.durationTime; + } else if (+a.startTime != +b.startTime) { return a.startTime - b.startTime; + } else { + return a.name < b.name ? -1 : 1; } }).forEach(function(event, i) { var line = self.lineEvents.length; @@ -858,16 +871,17 @@ Ox.Calendar = function(options, self) { marginLeft: -delta / getScrollbarFactor() + 'px' }, ms); if (!Ox.isUndefined(line)) { - scrollTo(line * 16 + 8 - self.$container.height() / 2, true); + scrollTo((line + 1) * 16 - self.$container.height() / 2, true); } }; function panToSelected() { // fixme: '0' should zoom to selected if selected is already centered // (both horizontally and vertically, the latter is a bit more work) + var event = getSelectedEvent(); self.options.selected !== '' && panTo( - getEventCenter(getSelectedEvent()), - getSelectedEventElement().data('line') + getEventCenter(event), + getEventLine(event.id) ); } @@ -900,7 +914,7 @@ Ox.Calendar = function(options, self) { event.id == self.options.selected || overlaps(event, calendarEvent) ) { - getEventElement(event).data({line: line}).appendTo(self.$lines[line]); + getEventElement(event).appendTo(self.$lines[line]); } }); }); @@ -978,7 +992,12 @@ Ox.Calendar = function(options, self) { self.$content.find('.OxSelected').removeClass('OxSelected'); if (id) { self.options.selected = id; - ($element || getEventElementById(id)).addClass('OxSelected'); + $element = $element || getEventElementById(id); + if ($element) { + $element.addClass('OxSelected'); + } else { + panToSelected(); + } // fixme: map event should also be 'select', not 'selectplace' that.triggerEvent('select', Ox.getObjectById(self.options.events, id)); } else { @@ -1053,6 +1072,7 @@ Ox.Calendar = function(options, self) { that.addEvent = function(event) { Ox.print('CALENDAR ADD EVENT', event) + event = getEventData(event); self.options.events.push(event); getLines(); renderCalendar(); @@ -1091,6 +1111,7 @@ Ox.Calendar = function(options, self) { if ($element) { getLines(); renderCalendar(); + panToSelected(); } }); return that; @@ -1107,7 +1128,7 @@ Ox.Calendar = function(options, self) { that.removeEvent = function() { Ox.print('REMOVE ... SELF.OPTIONS', self.options) - var index = Ox.getPositionById(self.options.events, self.selected); + var index = Ox.getPositionById(self.options.events, self.options.selected); self.options.events.splice(index, 1); getLines(); renderCalendar(); @@ -1118,7 +1139,6 @@ Ox.Calendar = function(options, self) { self.options.width = that.width(); self.options.height = that.height(); self.$zoomInput.options({size: self.options.width}); - getLines(); renderCalendar(); return that; }; diff --git a/source/Ox.UI/js/Calendar/Ox.ListCalendar.js b/source/Ox.UI/js/Calendar/Ox.ListCalendar.js index a7dee2cf..1b44358b 100644 --- a/source/Ox.UI/js/Calendar/Ox.ListCalendar.js +++ b/source/Ox.UI/js/Calendar/Ox.ListCalendar.js @@ -26,17 +26,11 @@ Ox.ListCalendar = function(options, self) { height: self.options.height + 'px' }); + self.durationCache = {}; + Ox.print('EVENT[0]', self.options.events[0]) self.columns = [ - { - addable: false, // fixme: implement - id: 'id', - title: 'Id', - unique: true, - visible: false, - width: 64 - }, { id: 'name', operator: '+', @@ -68,6 +62,9 @@ Ox.ListCalendar = function(options, self) { }, { id: 'start', + map: function(value) { + return Ox.parseDate(value); + }, operator: '-', title: 'Start', visible: true, @@ -75,17 +72,32 @@ Ox.ListCalendar = function(options, self) { }, { id: 'end', + map: function(value) { + return Ox.parseDate(value); + }, operator: '-', title: 'End', visible: true, width: 144 }, { - id: 'duration', + format: function(value, data) { + // return Ox.formatDateRangeDuration(data.start, data.end, true); + var key = data.start + ' - ' + data.end; + if (!self.durationCache[key]) { + self.durationCache[key] = Ox.formatDateRangeDuration(data.start, data.end, true); + } + return self.durationCache[key]; + }, + id: 'id', + map: function(value, data) { + return Ox.parseDate(data.end) - Ox.parseDate(data.start); + }, operator: '-', title: 'Duration', + unique: true, visible: true, - width: 144 + width: 256 }, { id: 'user', @@ -172,14 +184,16 @@ Ox.ListCalendar = function(options, self) { columns: self.columns, columnsRemovable: true, columnsVisible: true, - //items: Ox.clone(self.options.places), - items: self.options.events, + // we have to clone so that when self.options.events changes, + // self.$list.options({items: self.options.events}) still + // registers as a change + items: Ox.clone(self.options.events, true), pageLength: self.options.pageLength, scrollbarVisible: true, sort: self.options.sort }) .bindEvent({ - 'delete': removeItem, + 'delete': removeEvent, init: initList, // fixme: won't fire from static list key_0: function() { self.$calendar.panToEvent(); @@ -215,7 +229,7 @@ Ox.ListCalendar = function(options, self) { self.$calendar = Ox.Calendar({ date: new Date(0), - events: self.options.events, + events: Ox.clone(self.options.events, true), height: self.options.height, width: self.options.width - 514, zoom: 4 @@ -446,6 +460,8 @@ Ox.ListCalendar = function(options, self) { Ox.print('ADD', self.$calendar.getBounds()) 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 = {}, i = 1; event.name = 'Untitled'; @@ -454,50 +470,53 @@ Ox.ListCalendar = function(options, self) { }; event.alternativeNames = []; event.type = 'other'; - event.startTime = +new Date((+bounds.startTime + middle) / 2); - event.endTime = +new Date((+bounds.endTime + middle) / 2); - event.start = Ox.formatDate(event.startTime, '%Y-%m-%d %H:%M:%S', true); - event.end = Ox.formatDate(event.endTime, '%Y-%m-%d %H:%M:%S', true); + event.start = Ox.formatDate(startTime, '%Y-%m-%d %H:%M:%S', true); + event.end = Ox.formatDate(endTime, '%Y-%m-%d %H:%M:%S', true); Ox.print(event); self.options.addEvent(event, function(result) { - event.id = result.data.id; - self.options.events.push(event); - self.$list.options({ - items: Ox.clone(self.options.events), - selected: [event.id] - }); - self.$calendar.addEvent(event); - // fixme: duplicated - self.selectedEvent = event.id; - self.$eventName.options({title: event.name}); - self.$eventTitle.show(); - self.$eventForm.values(Ox.extend({}, event, { - end: event.current ? '' : event.end - })).show(); - self.$removeEventButton.show(); + if (result.status.code == '200') { + event.id = result.data.id; + self.options.events.push(event); + var time0 = +new Date() + self.$list.options({items: Ox.clone(self.options.events, true)}); + Ox.print('TIME TO SET LIST OPTIONS:', +new Date() - time0); + self.$calendar.addEvent(event); + selectEvent(event); + self.$nameInput.focusInput(); + } else { + alert(result.status.text); + } }); } function editEvent(key, value) { - var data = {id: self.selectedEvent}; + var id = self.selectedEvent, + index = Ox.getPositionById(self.options.events, id), + data = {id: id}; data[key] = value; - if (['start', 'end'].indexOf(key) > -1) { - self.$durationInput.options({ - value: Ox.formatDateRangeDuration( - self.$startInput.options('value'), - self.$endInput.options('value') - || Ox.formatDate(new Date(), '%Y-%m-%d %H%:%M:%S'), - true - ) - }); - } - if (['name', 'type', 'start', 'end'].indexOf(key) > -1) { - self.$calendar.editEvent(self.selectedEvent, key, value); - } self.options.editEvent(data, function(result) { - // ... + if (result.status.code == 200) { + self.options.events[index][key] = value; + self.$list.value(id, key, value); + if (['name', 'type', 'start', 'end'].indexOf(key) > -1) { + self.$calendar.editEvent(id, key, value); + } + if (key == 'name') { + self.$eventName.options({title: value}); + } else if (['start', 'end'].indexOf(key) > -1) { + self.$durationInput.options({ + value: Ox.formatDateRangeDuration( + self.$startInput.options('value'), + self.$endInput.options('value') + || Ox.formatDate(new Date(), '%Y-%m-%d %H%:%M:%S'), + true + ) + }); + } + } else { + alert(result.status.text); + } }); - } function initList(data) { @@ -528,26 +547,22 @@ Ox.ListCalendar = function(options, self) { } function removeEvent() { - self.options.removeEvent({id: self.selectedEvent}, function(result) { - var index = Ox.getPositionById(self.options.events, self.selectedEvent); - self.options.events.splice(index, 1); - self.$list.options({items: Ox.clone(self.options.events)}); - self.$calendar.removeEvent(); - // fixme: duplicated - self.selectedEvent = null; - self.$eventTitle.hide(); - self.$eventForm.hide(); - self.$removeEventButton.hide(); + var id = self.selectedEvent, + index = Ox.getPositionById(self.options.events, id); + self.options.removeEvent({id: id}, function(result) { + if (result.status.code == '200') { + self.options.events.splice(index, 1); + var time0 = +new Date(); + self.$list.options({items: Ox.clone(self.options.events, true)}); + Ox.print('TIME TO SET LIST OPTIONS:', +new Date() - time0); + self.$calendar.removeEvent(); + selectEvent({}); + } else { + alert(result.status.text); + } }); } - function removeItem(data) { - var id = data.ids[0]; - // fixme: events or callback functions?? - that.triggerEvent('removeevent', {id: id}); - self.$calendar.removeEvent(id); - } - function selectEvent(event) { self.$list.options({ selected: event.id ? [event.id] : [] @@ -576,24 +591,35 @@ Ox.ListCalendar = function(options, self) { } function updateList(key, value) { - var query = { - conditions: Ox.merge( + var events; + if (value === '') { + events = Ox.clone(self.options.events); + } else { + events = []; + self.options.events.forEach(function(event) { + if (( ['all', 'name'].indexOf(key) > -1 - ? [{key: 'name', value: value, operator: '='}] : [], + && event.name.toLowerCase().indexOf(value) > -1 + ) || ( ['all', 'alternativeNames'].indexOf(key) > -1 - ? [{key: 'alternativeNames', value: value, operator: '='}] : [] - ), - operator: key == 'all' ? '|' : '&' - }; - self.$list.options({ - items: function(data, callback) { - return pandora.api.findEvents(Ox.extend(data, { - query: query - }), callback); - } - }); + && event.alternativeNames.join('\n').toLowerCase().indexOf(value) > -1 + )) { + events.push(event) + } + }); + } + self.$list.options({items: events}); } + self.setOption = function(key, value) { + if (key == 'height') { + // fixme: should be .resizeList + self.$list.size(); + } else if (key == 'width') { + self.$calendar.resizeCalendar(); + } + }; + return that; }; \ No newline at end of file diff --git a/source/Ox.UI/js/Form/Ox.Form.js b/source/Ox.UI/js/Form/Ox.Form.js index dd713141..bd6635bf 100644 --- a/source/Ox.UI/js/Form/Ox.Form.js +++ b/source/Ox.UI/js/Form/Ox.Form.js @@ -138,6 +138,7 @@ Ox.Form = function(options, self) { //Ox.print('VALUES', values) return values; } else { + Ox.print('SET FORM VALUES', arguments[0]) Ox.forEach(arguments[0], function(value, key) { var index = getItemIndexById(key); //index > -1 && Ox.print(':::::::', key, value) diff --git a/source/Ox.UI/js/Form/Ox.Select.js b/source/Ox.UI/js/Form/Ox.Select.js index cc2dd4b9..e13f2472 100644 --- a/source/Ox.UI/js/Form/Ox.Select.js +++ b/source/Ox.UI/js/Form/Ox.Select.js @@ -43,11 +43,12 @@ Ox.Select = function(options, self) { size: 'medium', title: '', type: 'text', // can be 'text' or 'image' - value: [], + value: '', width: 'auto' }) // fixme: make default selection restorable // or allow for extra action items below options + // fixme: passing value has no effect .options(options) .addClass( 'OxSelect Ox' + Ox.toTitleCase(self.options.size) + ( @@ -148,6 +149,7 @@ Ox.Select = function(options, self) { function changeMenu(data) { //Ox.print('clickMenu: ', self.options.id, data) self.checked = self.optionGroup.checked(); + self.options.value = data.checked[0].id; self.$title && self.$title.html( self.options.title ? self.options.title : data.checked[0].title @@ -177,10 +179,13 @@ Ox.Select = function(options, self) { self.setOption = function(key, value) { if (key == 'value') { + Ox.print('SETTING VALUE OPTION', value) that.selectItem(value); } }; + // FIXME: selected() _and_ selectItem() _and_ value() ??? + /*@ selected gets selected item () -> returns object of selected items with id, title @@ -223,6 +228,8 @@ Ox.Select = function(options, self) { //Ox.print('selected::', that.selected()) return that.selected()[0].id; } else { + that.selectItem(arguments[0]); + return that; /* Ox.print('ELSE'); that.selectItem(arguments[0]); diff --git a/source/Ox.UI/js/List/Ox.List.js b/source/Ox.UI/js/List/Ox.List.js index c1670dad..7eb6aadd 100644 --- a/source/Ox.UI/js/List/Ox.List.js +++ b/source/Ox.UI/js/List/Ox.List.js @@ -192,7 +192,8 @@ Ox.List = function(options, self) { } if (!self.isAsync) { - self.$page = Ox.Element() + self.$pages = []; + self.$pages[0] = Ox.Element() .addClass('OxPage') .css({ left: self.listMargin / 2 + 'px', @@ -426,6 +427,7 @@ Ox.List = function(options, self) { var height = getHeight(), lastItemHeight = height % self.options.itemHeight || self.options.itemHeight, visibleItems = Math.ceil(height / self.options.itemHeight); + Ox.print('FILL', self.listLength, visibleItems); if (self.listLength < visibleItems) { Ox.range(self.listLength, visibleItems).forEach(function(v) { var $item = Ox.ListItem({ @@ -685,20 +687,27 @@ Ox.List = function(options, self) { } function loadItems() { - self.$page.empty(); + self.$pages[0].empty(); self.$items = []; + var timeC = 0, timeA = 0; self.options.items.forEach(function(item, pos) { // fixme: duplicated + var time0 = +new Date(); self.$items[pos] = Ox.ListItem({ construct: self.options.construct, data: item, position: pos, unique: self.options.unique }); + timeC += +new Date() - time0; isSelected(pos) && self.$items[pos].addClass('OxSelected'); - self.$items[pos].appendTo(self.$page); + var time0 = +new Date(); + self.$items[pos].appendTo(self.$pages[0]); + timeA += +new Date() - time0; }); + fillFirstPage(); self.selected.length && scrollToPosition(self.selected[0]); + Ox.print('CONSTRUCT:', timeC, 'APPEND:', timeA); // that.triggerEvent('init', {items: self.options.items.length}); // fixme: do sync lists need to trigger init? // will this only be reached in sync lists? @@ -1169,6 +1178,7 @@ Ox.List = function(options, self) { // fixme: no case where callback is set // note: can't use selectNone here, // since it'd trigger a select event + Ox.print('SET SELECTED', ids) var counter = 0; self.$items.forEach(function($item, pos) { if (isSelected(pos)) { @@ -1345,7 +1355,7 @@ Ox.List = function(options, self) { if (!self.isAsync) { selectedIds = getSelectedIds(); self.options.items.forEach(function(item) { - sort[item.id] = map ? map(item[key]) : item[key]; + sort[item.id] = map ? map(item[key], item) : item[key]; }); self.options.items.sort(function(a, b) { var aValue = sort[a.id], @@ -1381,9 +1391,9 @@ Ox.List = function(options, self) { // fixme: this could be used to change the list // from sync to async or vice versa, which wouldn't work if (Ox.isArray(value)) { + self.listLength = value.length; updateSelected(); updateSort(); - loadItems(); } else { updateQuery(); } @@ -1538,11 +1548,20 @@ Ox.List = function(options, self) { () -> the list @*/ that.reloadPages = function() { - var page = self.page; - clear(); - self.page = page - that.$content.empty(); - loadPages(self.page); + // this is called by TextList when the column layout changes + var page, scrollLeft, scrollTop; + if (!self.isAsync) { + scrollLeft = that.scrollLeft(); + scrollTop = that.scrollTop(); + loadItems(); + that.scrollLeft(scrollLeft).scrollTop(scrollTop); + } else { + page = self.page; + clear(); + self.page = page + that.$content.empty(); + loadPages(self.page); + } return that; }; diff --git a/source/Ox.UI/js/List/Ox.TextList.js b/source/Ox.UI/js/List/Ox.TextList.js index 512bcd45..0ed389b5 100644 --- a/source/Ox.UI/js/List/Ox.TextList.js +++ b/source/Ox.UI/js/List/Ox.TextList.js @@ -404,30 +404,36 @@ Ox.TextList = function(options, self) { self.visibleColumns.forEach(function(v, i) { var clickable = Ox.isBoolean(v.clickable) ? v.clickable : v.clickable(data), editable = Ox.isBoolean(v.editable) ? v.editable : v.editable(data), + $cell; + if (v.tooltip) { $cell = Ox.Element({ - tooltip: v.tooltip ? function() { - return self.options.selected.indexOf(data[self.unique]) > -1 - ? (Ox.isString(v.tooltip) ? v.tooltip : v.tooltip(data)) : ''; - } : null - }) - .addClass( - 'OxCell OxColumn' + Ox.toTitleCase(v.id) + - (clickable ? ' OxClickable' : '') + - (editable ? ' OxEditable' : '') - ) - .css({ - width: (self.columnWidths[i] - (self.options.columnsVisible ? 9 : 8)) + 'px', - borderRightWidth: (self.options.columnsVisible ? 1 : 0) + 'px', - textAlign: v.align - }) - .html(v.id in data ? formatValue(v.id, data[v.id], data) : '') - .appendTo($item); + tooltip: function() { + return self.options.selected.indexOf(data[self.unique]) > -1 + ? (Ox.isString(v.tooltip) ? v.tooltip : v.tooltip(data)) : ''; + } + }); + } else { + // this is faster + $cell = $('
'); + } + $cell.addClass( + 'OxCell OxColumn' + Ox.toTitleCase(v.id) + + (clickable ? ' OxClickable' : '') + + (editable ? ' OxEditable' : '') + ) + .css({ + width: (self.columnWidths[i] - (self.options.columnsVisible ? 9 : 8)) + 'px', + borderRightWidth: (self.options.columnsVisible ? 1 : 0) + 'px', + textAlign: v.align + }) + // if the column id is not in data, we're constructing an empty cell + .html(v.id in data ? formatValue(v.id, data[v.id], data) : '') + .appendTo($item); }); return $item; } function dragstartColumn(id, e) { - //Ox.print(that.$body.scrollLeft(), '??') self.drag = { columnOffsets: getColumnOffsets(), listOffset: that.$element.offset().left - that.$body.scrollLeft(), @@ -440,7 +446,6 @@ Ox.TextList = function(options, self) { self.$heads[self.drag.startPos].addClass('OxDrag').css({ // fixme: why does the class not work? cursor: 'move' }); - //Ox.print('columnOffsets', self.drag.columnOffsets) } function dragColumn(id, e) { @@ -824,6 +829,7 @@ Ox.TextList = function(options, self) { width: width }) .bind({ + blur: submit, mousedown: function(e) { // keep mousedown from reaching list e.stopPropagation(); diff --git a/source/Ox.UI/js/Map/Ox.ListMap.js b/source/Ox.UI/js/Map/Ox.ListMap.js index c4143566..fab4defa 100644 --- a/source/Ox.UI/js/Map/Ox.ListMap.js +++ b/source/Ox.UI/js/Map/Ox.ListMap.js @@ -65,10 +65,13 @@ Ox.ListMap = function(options, self) { }, id: 'countryCode', resizable: false, // fixme: implement + /* + // fixme: why does this not work? it does in folderBrowserList title: $('').attr({ src: Ox.UI.getImageURL('symbolFlag') - // fixme: why does this not work? it does in folderBrowserList }), + */ + title: '\u2691', visible: true, width: 16 }, @@ -92,8 +95,8 @@ Ox.ListMap = function(options, self) { }, { id: 'geoname', - map: function(v) { - var names = v.split(', '); + map: function(value) { + var names = value.split(', '); if (!Ox.getCountryByGeoname(names[names.length - 1])) { names.push('~'); } @@ -824,15 +827,13 @@ Ox.ListMap = function(options, self) { setOption setOption @*/ self.setOption = function(key, value) { - Ox.print('ONCHANGE') - if (key == 'height' || key == 'width') { - Ox.print('ONCHANGE...') - self.$map.options({ - height: self.options.height, - width: self.options.width - }) + if (key == 'height') { + self.$list.size(); + self.$map.resizeMap(); } else if (key == 'selected') { self.$list.options({selected: value}); + } else if (key == 'width') { + self.$map.resizeMap(); } } diff --git a/source/Ox.UI/js/Map/Ox.Map.js b/source/Ox.UI/js/Map/Ox.Map.js index 78ce7a42..dbc8f8db 100644 --- a/source/Ox.UI/js/Map/Ox.Map.js +++ b/source/Ox.UI/js/Map/Ox.Map.js @@ -743,14 +743,12 @@ Ox.Map = function(options, self) { Ox.print('init', mapBounds.getSouthWest(), mapBounds.getNorthEast(), mapBounds.getCenter()) - updateFormElements(); - self.elevationService = new google.maps.ElevationService(); self.geocoder = new google.maps.Geocoder(); self.maxZoomService = new google.maps.MaxZoomService(); self.center = mapBounds ? mapBounds.getCenter() : new google.maps.LatLng(0, 0); - self.zoom = 1; // fixme: should depend on height + self.zoom = self.minZoom; that.map = self.map = new google.maps.Map(self.$map.$element[0], { center: self.center, disableDefaultUI: true, @@ -772,12 +770,14 @@ Ox.Map = function(options, self) { selectPlace(self.options.selected, true); } else { mapBounds && self.map.fitBounds(mapBounds); - ///* if (self.map.getZoom() < self.minZoom) { self.map.setZoom(self.minZoom); } - //*/ } + updateFormElements(); + + // fixme: this is just guessing + // setTimeout(updateFormElements, 2500); self.places = []; if (!self.isAsync) { @@ -1239,7 +1239,12 @@ Ox.Map = function(options, self) { function updateFormElements() { var width = that.width(); - self.$zoomInput && constructZoomInput(); + if (self.options.zoombar) { + getMaxZoom(function(zoom) { + self.maxZoom = zoom; + constructZoomInput(); + }); + } if (self.options.statusbar) { self.$placeNameInput.options({ width: Math.floor((width - 132) / 2) @@ -1275,9 +1280,9 @@ Ox.Map = function(options, self) { } self.setOption = function(key, value) { - /*if (key == 'height' || key == 'width') { - resizeMap(); - } else */if (key == 'places') { + if (key == 'height' || key == 'width') { + that.resizeMap(); + } else if (key == 'places') { //fixme: should zoom to new bounds zoom(0); } else if (key == 'selected') { @@ -1385,7 +1390,6 @@ Ox.Map = function(options, self) { self.options.width = that.$element.width(); self.mapHeight = getMapHeight(); self.minZoom = getMinZoom(); - Ox.print('map w/h', self.options.width, self.options.height) self.$map.css({ height: self.mapHeight + 'px', width: self.options.width + 'px' diff --git a/source/Ox.UI/js/Window/Ox.Dialog.js b/source/Ox.UI/js/Window/Ox.Dialog.js index aa33acbd..a106d0ae 100644 --- a/source/Ox.UI/js/Window/Ox.Dialog.js +++ b/source/Ox.UI/js/Window/Ox.Dialog.js @@ -297,6 +297,10 @@ Ox.Dialog = function(options, self) { height: self.options.maxHeight }, true); self.maximized = !self.maximized; + that.triggerEvent('resize', { + width: self.options.width, + height: self.options.height + }); } function mousedownLayer() { @@ -331,6 +335,12 @@ Ox.Dialog = function(options, self) { left: left, top: top }), animate); + /* + that.triggerEvent('resize', { + width: self.options.width, + height: self.options.height + }); + */ } function resizestart(event) { @@ -512,6 +522,10 @@ Ox.Dialog = function(options, self) { function resizeend() { that.unwrap(); + that.triggerEvent('resizeend', { + width: self.options.width, + height: self.options.height + }); } function setButtons() { diff --git a/source/Ox.UI/themes/classic/css/classic.css b/source/Ox.UI/themes/classic/css/classic.css index 42761923..8fdc9a49 100644 --- a/source/Ox.UI/themes/classic/css/classic.css +++ b/source/Ox.UI/themes/classic/css/classic.css @@ -111,13 +111,19 @@ Calendar .OxThemeClassic .OxCalendar .OxLine > .OxEvent { color: rgb(0, 0, 0); } +.OxThemeClassic .OxCalendar .OxLine > .OxEvent.OxSelected { + box-shadow: inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0), + inset 0 0 1px rgb(0, 0, 0); +} .OxThemeClassic .OxCalendar .OxOverlay div:nth-child(even) { - border-top: 1px solid rgba(0, 0, 0, 0.5); - border-bottom: 1px solid rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.25); + box-shadow: inset 0 0 2px rgb(0, 0, 0); } .OxThemeClassic .OxCalendar .OxOverlay div:nth-child(odd) { - background-color: rgba(255, 255, 255, 0.5); + background-color: rgba(255, 255, 255, 0.25); } /* diff --git a/source/Ox.UI/themes/modern/css/modern.css b/source/Ox.UI/themes/modern/css/modern.css index 3e4f3750..6bcd4784 100644 --- a/source/Ox.UI/themes/modern/css/modern.css +++ b/source/Ox.UI/themes/modern/css/modern.css @@ -110,13 +110,19 @@ Calendar .OxThemeModern .OxCalendar .OxLine > .OxEvent { color: rgb(255, 255, 255); } +.OxThemeModern .OxCalendar .OxLine > .OxEvent.OxSelected { + box-shadow: inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255), + inset 0 0 1px rgb(255, 255, 255); +} .OxThemeModern .OxCalendar .OxOverlay div:nth-child(even) { - border-top: 1px solid rgba(255, 255, 255, 0.5); - border-bottom: 1px solid rgba(255, 255, 255, 0.5); + background-color: rgba(255, 255, 255, 0.25); + box-shadow: inset 0 0 2px rgb(255, 255, 255); } .OxThemeModern .OxCalendar .OxOverlay div:nth-child(odd) { - background-color: rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.25); } diff --git a/source/Ox/js/Format.js b/source/Ox/js/Format.js index 2ff2e914..14a549e9 100644 --- a/source/Ox/js/Format.js +++ b/source/Ox/js/Format.js @@ -279,6 +279,7 @@ Ox.formatDateRange Formats a date range as a string 'Sun, Jan 1, 50 BC, 00:00:00 - 23:59:59' @*/ Ox.formatDateRange = function(start, end, utc) { + end = end || Ox.formatDate(new Date(), '%Y-%m-%d'); var isOneUnit = false, range = [start, end], strings, @@ -370,6 +371,7 @@ Ox.formatDateRangeDuration Formats the duration of a date range as a string '1 month' @*/ Ox.formatDateRangeDuration = function(start, end, utc) { + end = end || Ox.formatDate(new Date(), '%Y-%m-%d'); var date = Ox.parseDate(start, utc), dates = [start, end].map(function(str) { return Ox.parseDate(str, utc); @@ -380,19 +382,30 @@ Ox.formatDateRangeDuration = function(start, end, utc) { Ox.forEach(keys, function(key, i) { while (true) { if (key == 'month') { + // set the day to the same day in the next month, + // or to its last day if the next month is shorter + var day = Ox.getDate(date, utc); Ox.setDate(date, Math.min( - Ox.getDate(date, utc), + day, Ox.getDaysInMonth( Ox.getFullYear(date, utc), - Ox.getMonth(date, utc) + 2 + Ox.getMonth(date, utc) + 2, + utc ) ), utc); } + // advance the date by one unit Ox['set' + parts[i]](date, Ox['get' + parts[i]](date, utc) + 1, utc); if (date <= dates[1]) { + // still within the range, add one unit values[i] = (values[i] || 0) + 1; } else { + // outside the range, rewind the date by one unit Ox['set' + parts[i]](date, Ox['get' + parts[i]](date, utc) - 1, utc); + if (key == 'month') { + // and revert to original day + Ox.setDate(date, day, utc); + } break; } }