Changeset 06b76b in indico
- Timestamp:
- 01/24/12 11:15:33 (17 months ago)
- Branches:
- master, hello-world-walkthrough, ipv6, v0.98-series, v0.98.2, v0.98.3, v0.99, b8c30da8ebdbdcbd675a873997cc3e95f567de49, 4287315ec967a3da168d83963c14001db8487d53
- Children:
- 44e7c3
- Parents:
- c82c67
- git-author:
- Pedro Ferreira <jose.pedro.ferreira@…> (10/28/11 14:28:22)
- git-committer:
- Pedro Ferreira <jose.pedro.ferreira@…> (01/24/12 11:15:33)
- Files:
-
- 5 added
- 16 edited
-
etc/js/indico.cfg (modified) (1 diff)
-
indico/MaKaC/common/Configuration.py (modified) (1 diff)
-
indico/MaKaC/services/implementation/base.py (modified) (1 diff)
-
indico/MaKaC/services/implementation/schedule.py (modified) (2 diffs)
-
indico/MaKaC/webinterface/tpls/ConfModifScheduleGraphic.tpl (modified) (1 diff)
-
indico/MaKaC/webinterface/tpls/ConferenceTimeTable.tpl (modified) (1 diff)
-
indico/MaKaC/webinterface/tpls/js/vars.js.tpl (modified) (1 diff)
-
indico/htdocs/css/Default.css (modified) (5 diffs)
-
indico/htdocs/images/pointer_tip.png (added)
-
indico/htdocs/images/src/tt_time.svg (added)
-
indico/htdocs/images/tt_time.png (added)
-
indico/htdocs/js/indico/Core/Data.js (modified) (1 diff)
-
indico/htdocs/js/indico/Core/Dialogs/Util.js (modified) (1 diff)
-
indico/htdocs/js/indico/Management/Timetable.js (modified) (6 diffs)
-
indico/htdocs/js/indico/Timetable/Base.js (modified) (20 diffs)
-
indico/htdocs/js/indico/Timetable/DragAndDrop.js (added)
-
indico/htdocs/js/indico/Timetable/Draw.js (modified) (27 diffs)
-
indico/htdocs/js/indico/Timetable/Layout.js (modified) (8 diffs)
-
indico/htdocs/js/indico/Timetable/Loader.js (modified) (1 diff)
-
indico/htdocs/js/indico/Timetable/Management.js (modified) (4 diffs)
-
indico/htdocs/js/indico/Timetable/Undo.js (added)
Legend:
- Unmodified
- Added
- Removed
-
etc/js/indico.cfg
refa98d r06b76b 61 61 Layout.js 62 62 Base.js 63 DragAndDrop.js 64 Undo.js 63 65 Draw.js 64 66 Management.js -
indico/MaKaC/common/Configuration.py
r1a3173 r06b76b 115 115 "indico_co": "indico_co.png", 116 116 "login": "pict_login.png", 117 "tt_time": "tt_time.png", 117 118 "table": "img_table.png", 118 119 "lectureMenu": "pict_event_negb.png", -
indico/MaKaC/services/implementation/base.py
rb58f4b r06b76b 96 96 value = self._paramList.get(paramName) 97 97 98 99 98 if (not allowEmpty) and (value == None): 100 99 raise EmptyParameterException(paramName) -
indico/MaKaC/services/implementation/schedule.py
r05eb0f r06b76b 1074 1074 self._sessionId = pManager.extract("sessionId", pType=str, allowEmpty=True, defaultValue=None) 1075 1075 self._sessionSlotId = pManager.extract("sessionSlotId", pType=str, allowEmpty=True, defaultValue=None) 1076 1077 def _performOperation(self): 1078 1076 self._keepTime = pManager.extract("keepTime", pType=bool, allowEmpty=True, defaultValue=False) 1077 1078 def _performOperation(self): 1079 1079 if (self._sessionId != None and self._sessionSlotId != None): 1080 1080 self._schEntry = self._conf.getSessionById(self._sessionId).getSlotById(self._sessionSlotId).getSchedule().getEntryById(self._schEntryId) … … 1113 1113 self._schEntry.setDuration(dur=slot.getDuration()) 1114 1114 else: 1115 self._schEntry.setStartDate(slot.getSchedule().calculateEndDate()) 1115 if self._keepTime: 1116 self._schEntry.setStartDate(oldDate) 1117 else: 1118 self._schEntry.setStartDate(slot.getSchedule().calculateEndDate()) 1116 1119 #self._schEntry.setDuration(dur=session.getContribDuration()) 1117 1120 # add it to new container -
indico/MaKaC/webinterface/tpls/ConfModifScheduleGraphic.tpl
rc0de5a r06b76b 1 1 <div class="groupTitleNoBorder">${ _("Timetable")} <em>(${ _("from") } ${ start_date } ${ _("to") } ${ end_date } <a href=${ editURL }>[${_("edit")}]</a> ${_("Timezone")}: ${ timezone })</em></div> 2 2 3 <div id="timetableDiv" style="position: relative;"> 3 4 -
indico/MaKaC/webinterface/tpls/ConferenceTimeTable.tpl
r1a8f22 r06b76b 1 2 1 <div id="timetable" style="position: relative;"> 3 2 -
indico/MaKaC/webinterface/tpls/js/vars.js.tpl
r6d8443 r06b76b 85 85 indico_small: "${ iconFileName("indico_small")}", 86 86 protected: "${ iconFileName("protected")}", 87 calendarWidget: "${ iconFileName("calendarWidget") }" 87 calendarWidget: "${ iconFileName("calendarWidget") }", 88 tt_time: "${ iconFileName("tt_time") }" 88 89 }, 89 90 FileTypeIcons: -
indico/htdocs/css/Default.css
rc82c67 r06b76b 5013 5013 } 5014 5014 5015 /* Timetable drag n drop, 5016 droppable styles starts here. */ 5015 .timetableBlock { 5016 box-shadow: 0px 0px 5px #DDD; 5017 } 5018 5019 /* Timetable drag n drop */ 5020 5021 #tt_hour_tip { 5022 cursor: pointer; 5023 overflow: auto; 5024 background: white; 5025 position: absolute; 5026 z-index: 1; 5027 } 5028 5029 #tt_hour_tip:hover { 5030 opacity: 0.7; 5031 } 5032 5033 .hourLine { 5034 position: absolute; 5035 border-top: 1px solid #E8E8E8; 5036 font-size: 11px; 5037 } 5038 5039 .ui-state-disabled.hourLine { 5040 opacity: 1.0 !important; 5041 } 5042 5043 .ui-droppable-disabled { 5044 opacity: 0.7 !important; 5045 } 5017 5046 5018 5047 /* For when the Shift is held down */ … … 5048 5077 5049 5078 div.ui-draggable-dragging { 5050 border: 3px solid gold;5051 /*background-color: gold;*/5052 /*To make the current dragged element5053 on top of everything*/5054 5079 z-index: 9000; 5055 } 5056 5057 div.dragTip { 5058 /* Just over 9000! (To be "above" the draggable, which has z-index 9000) */ 5059 z-index: 9001; 5060 position: absolute; 5061 width: 100%; 5062 top: 350; 5063 border-top: 1px dotted red; 5064 font-weight: bold; 5080 opacity: 0.5; 5065 5081 } 5066 5082 … … 5793 5809 } 5794 5810 5795 div.blockMoveProgressText { 5796 /* 5797 position: fixed; 5798 bottom: 0px;*/ 5811 #tt_status_info .text { 5799 5812 padding: 3px 8px 3px; 5800 5813 text-align: center; 5801 color: #DDD; 5802 } 5803 5804 div.blockMoveProgressImage { 5805 background: transparent url("../images/load_lightblue.gif") no-repeat center center; 5806 padding-bottom: 49px; 5807 } 5808 5809 div.blockMoveProgress { 5810 width: 100px; 5811 background-color: #424242; 5814 color: #aaa; 5815 float: right; 5816 } 5817 5818 #tt_status_info img { 5819 margin-top: 2px; 5820 } 5821 5822 #tt_status_info { 5823 background: #fefefe; 5824 border: 1px solid #eee; 5825 padding: 5px; 5812 5826 position: fixed; 5813 bottom: 1px;5814 left: 91.8%;5827 bottom: 5px; 5828 right: 5px; 5815 5829 -moz-border-radius: 5px; 5816 5830 -webkit-border-radius: 5px; 5831 opacity: 0.9; 5832 box-shadow: 0px 0px 2px rgba(220, 220, 200, 0.4); 5817 5833 } 5818 5834 … … 7388 7404 background: white url("../images/drag.png") left top no-repeat; 7389 7405 } 7406 7390 7407 .arrow { 7391 7408 background: #ECECEC; … … 7576 7593 } 7577 7594 7595 #dragTip { 7596 position: absolute; 7597 background: #f0f0f0; 7598 border: 1px solid #aaa; 7599 border-radius: 4px; 7600 font-size: 10px; 7601 padding: 4px; 7602 opacity: 0.7; 7603 box-shadow: 0px 0px 4px rgba(0,0,0,0.3); 7604 } 7605 7606 #dragTip .pointer { 7607 position: absolute; 7608 background: url('../images/pointer_tip.png'); 7609 height: 7px; 7610 width: 5px; 7611 top: 6px; 7612 right: -5px; 7613 } 7614 7615 .ui-resizable-resizing { 7616 opacity: 0.9; 7617 z-index: 1000; 7618 } -
indico/htdocs/js/indico/Core/Data.js
r791f15 r06b76b 166 166 dateTimeIndicoToJS: function(obj) { 167 167 m1 = obj.date.match(/(\d+)[\-\/](\d+)[\-\/](\d+)/); 168 m2 = obj.time.match(/(\d+):(\d+) :(\d+)/);169 170 171 var date = new Date(m1[1],m1[2] - 1,m1[3] );168 m2 = obj.time.match(/(\d+):(\d+)(?::(\d+))?/); 169 170 171 var date = new Date(m1[1],m1[2] - 1,m1[3]||0); 172 172 setTime(date, [m2[1],m2[2],m2[3]]); 173 173 -
indico/htdocs/js/indico/Core/Dialogs/Util.js
r791f15 r06b76b 20 20 }, 21 21 22 blockMoveProgress: function(text) { 23 var message = (text != undefined) ? $T(text) : ""; 24 var loadingImage = $('<div class= "blockMoveProgressImage"></div>'); 25 var loadingText = $('<div class="blockMoveProgressText"></div>').html(message); 26 var progress = $('<div class="blockMoveProgress"></div>').append(loadingImage, loadingText); 22 ttStatusInfo: function(text) { 23 var stext = $('<div class="text"></div>').text(text ? $T(text) : null); 24 var image = $('<img/>', { 25 src: "images/loading.gif", 26 alt: $T('Loading...') 27 }); 27 28 28 $('body').append(progress); 29 var progress = $('<div id="tt_status_info"></div>'). 30 append(image, stext); 31 32 if (!$('#tt_status_info').length) { 33 $('body').append(progress); 34 } else { 35 $('#tt_status_info').replaceWith(progress); 36 } 37 29 38 return function() { 30 $(progress).remove();39 $(progress).remove(); 31 40 }; 32 41 }, -
indico/htdocs/js/indico/Management/Timetable.js
r791f15 r06b76b 1035 1035 1036 1036 // disable the radio button where the item already belongs to 1037 if (!this.inSession && this.startDate.replaceAll('-', '') == currentDay) {1037 if (!this.inSession && Util.formatDateTime(this.eventData.startDate, IndicoDateTimeFormats.Ordinal) == currentDay) { 1038 1038 rb.dom.disabled = 'disabled'; 1039 1039 } … … 1056 1056 rb.dom.value = value.sessionId + ':' + value.sessionSlotId; 1057 1057 1058 if (this.inSession && value.sessionId == this. sessionId && value.sessionSlotId == this.slotId) {1058 if (this.inSession && value.sessionId == this.eventData.sessionId && value.sessionSlotId == this.eventData.sessionSlotId) { 1059 1059 rb.dom.disabled = 'disabled'; 1060 1060 } … … 1108 1108 1109 1109 var value = self.getChosenValue(); 1110 self.handleBlockMove(self, value); 1111 1112 var killProgress = IndicoUI.Dialogs.Util.progress($T('Moving the entry...')); 1113 1114 indicoRequest(self.managementActions.methods[self.inSession?'SessionEntry':'Event'].moveEntry, { 1115 value : value, 1116 conference : self.confId, 1117 scheduleEntryId : self.scheduleEntryId, 1118 sessionId : self.sessionId, 1119 sessionSlotId : self.slotId 1120 }, function(result, error) { 1121 if (error) { 1122 killProgress(); 1123 IndicoUtil.errorReport(error); 1124 } else { 1125 // change json and repaint timetable 1126 self.managementActions.timetable._updateMovedEntry(result, result.old.id); 1127 killProgress(); 1128 self.close(); 1129 } 1130 }); 1110 self.managementActions.moveToSession(self.eventData, value, 'drop'); 1131 1111 }], 1132 1112 [$T('Cancel'), function() { … … 1138 1118 draw: function() { 1139 1119 var self = this; 1140 this.inSession = true; 1141 1142 if (self.sessionId === null && self.slotId === null) { 1120 1121 if (this.eventData.sessionId === null && this.eventData.slotId === null) { 1143 1122 this.inSession = false; 1144 1123 } 1145 1124 // populate the tabslist 1146 var tabData = self.topLevelTimetableData;1125 var tabData = this.topLevelTimetableData; 1147 1126 1148 1127 // sort tabs according to days … … 1163 1142 var contribLocation = null; 1164 1143 if (this.inSession) { 1165 contribLocation = self.topLevelTimetableData[self.currentDay]['s' + self.sessionId + 'l' + self.slotId].title + 1144 contribLocation = self.topLevelTimetableData[this.currentDay] 1145 ['s' + this.eventData.sessionId + 'l' + this.eventData.sessionSlotId].title + 1166 1146 " (interval #" + self.slotId + ")"; 1167 1147 } else { … … 1206 1186 this.tabWidget.postDraw(); 1207 1187 this.ExclusivePopupWithButtons.prototype.postDraw.call(this); 1208 },1209 1210 /* Takes care of moving a contribution/timeblock to another session/timetable.1211 * This goes for both "drag and drop" as well as the regular "MoveEntry Dialog clicking"*/1212 handleBlockMove: function(eventData, value) {1213 var self = this;1214 1215 // if nothing has been selected yet1216 if (!value) {1217 return false;1218 1188 } 1219 1220 //Displays a "loading ..." div at the righthand bottom side1221 var killProgress = IndicoUI.Dialogs.Util.blockMoveProgress("Moving the entry...");1222 1223 self.inSession = true;1224 if (eventData.sessionId == null && eventData.sessionSlotId == null) {1225 self.inSession = false;1226 }1227 1228 indicoRequest(self.managementActions.methods[self.inSession?'SessionEntry':'Event'].moveEntry, {1229 value : value,1230 conference : self.confId,1231 scheduleEntryId : eventData.scheduleEntryId,1232 sessionId : eventData.sessionId,1233 sessionSlotId : self.slotId1234 }, function(result, error) {1235 if (error) {1236 killProgress();1237 IndicoUtil.errorReport(error);1238 } else {1239 // change json and repaint timetable1240 self.managementActions.timetable._updateMovedEntry(result, result.old.id);1241 killProgress();1242 self.close();1243 }});1244 }1245 1189 }, 1246 function(managementActions, timetable, entryType, sessionId, slotId, currentDay, scheduleEntryId, confId, startDate) { 1247 this.managementActions = managementActions; 1248 this.timetableData = timetable.getData(); 1249 this.topLevelTimetableData = timetable.parentTimetable?timetable.parentTimetable.getData():this.timetableData; 1250 this.timetable = timetable ; 1251 this.entryType = entryType; 1252 this.sessionId = sessionId; 1253 this.slotId = slotId; 1254 this.currentDay = currentDay; 1255 this.scheduleEntryId = scheduleEntryId; 1256 this.confId = confId; 1257 this.startDate = startDate; 1258 1259 var self = this; 1260 1261 this.ExclusivePopupWithButtons($T("Move Timetable Entry"), 1190 function(managementActions, timetable, eventData, currentDay) { 1191 this.managementActions = managementActions; 1192 this.timetableData = timetable.getData(); 1193 this.topLevelTimetableData = timetable.parentTimetable?timetable.parentTimetable.getData():this.timetableData; 1194 this.timetable = timetable; 1195 this.currentDay = currentDay; 1196 this.eventData = eventData; 1197 1198 this.inSession = (eventData.sessionId != null) && (eventData.sessionSlotId != null); 1199 1200 var self = this; 1201 1202 this.ExclusivePopupWithButtons($T("Move Timetable Entry"), 1262 1203 function() { 1263 self.close();1204 self.close(); 1264 1205 }); 1265 });1206 }); 1266 1207 1267 1208 -
indico/htdocs/js/indico/Timetable/Base.js
r791f15 r06b76b 52 52 $('<div/>').css('display', 'block'), 53 53 this.legend, 54 this.header .dom,54 this.header, 55 55 timetableDiv.dom, 56 56 this.loadingIndicator.dom).get(); … … 68 68 getData: function() { 69 69 return this.data; 70 }, 71 72 get_elem: function(blkId) { 73 return $(this.getTimetableDrawer()._blockMap[blkId]); 70 74 }, 71 75 … … 97 101 }, 98 102 103 setSelectedTab: function(val) { 104 // same as inherited, but return deferred 105 var dfr = $.Deferred(); 106 $('body').one('timetable_ready', function() { 107 dfr.resolve(); 108 }); 109 this.LookupTabWidget.prototype.setSelectedTab.call(this, val) 110 return dfr.promise(); 111 }, 112 99 113 getTimetableDrawer: function() { 100 114 return this.timetableDrawer; … … 135 149 }, 136 150 137 _shiftKeyListener: function() {138 var indicatorDiv = $('.shiftIndicator');139 140 //If its not already drawn/appended141 if(!(indicatorDiv.length > 0)) {142 indicatorDiv = (Html.div('shiftIndicator', $T("Shifting later entries ENABLED"))).dom;143 $('body').append(indicatorDiv);144 }145 146 //< Keyboard Key "Shift" held down > listener for shifting while dragging blocks147 $(window).keydown(function(e) {148 //if Shift is pushed down149 if(e.keyCode == '16') {150 $(window).data('shiftIsPressed', true);151 $(indicatorDiv).fadeIn("fast");152 }}).keyup(function(e){153 if(e.keyCode == '16') {154 $(window).data('shiftIsPressed', false);155 $(indicatorDiv).fadeOut("fast");156 }157 });158 159 $(window).data('shiftIsPressed', false); //default value is false160 }161 151 }, 162 152 function(data, width, wrappingElement, detailLevel, managementMode) { 163 153 var self = this; 164 this._shiftKeyListener();165 166 154 this.data = data; 167 155 … … 448 436 449 437 switchToInterval : function(intervalId) { 438 var dfr = $.Deferred(); 450 439 this.disable(); 451 440 … … 466 455 var content = this.intervalTimeTable.draw(); 467 456 this.canvas.html(content[0]); 457 this.intervalTimeTable.postDraw(); 468 458 $(this.menu.dom).hide(); 469 459 460 $('body').trigger('timetable_switch_interval', this.intervalTimeTable); 461 462 dfr.resolve(); 463 return dfr.promise(); 470 464 }, 471 465 … … 474 468 }, 475 469 476 switchToTopLevel : function() { 470 switchToTopLevel : function(day) { 471 var dfr = $.Deferred(); 477 472 this.enable(); 478 this.setSelectedTab( this.currentDay);473 this.setSelectedTab(day || this.currentDay); 479 474 $(this.menu.dom).show(); 480 475 this._generateContent(this.getSelectedPanel()); 481 476 this.timetableDrawer.redraw(); 477 $('body').trigger('timetable_switch_toplevel', this); 478 479 dfr.resolve(); 480 return dfr.promise(); 482 481 } 483 482 }, … … 592 591 }, 593 592 593 postDraw: function() { 594 this.timetableDrawer.postDraw(); 595 }, 596 594 597 setData: function(data) { 595 598 var day = IndicoUtil.formatDate2(IndicoUtil.parseJsonDate(data.startDate)); … … 622 625 623 626 }, 624 function(parent, width, wrappingElement, managementActions ) {627 function(parent, width, wrappingElement, managementActions, layout) { 625 628 626 629 this.managementActions = managementActions; … … 632 635 this.loadingIndicator, 633 636 !!managementActions, 634 managementActions); 637 managementActions, 638 layout || 'compact'); 635 639 }); 636 640 … … 694 698 }, 695 699 700 701 _updateMovedEntry: function(result, oldEntryId) { 702 return this._updateEntry(result, oldEntryId, function(data){ 703 704 var oldDay = Util.formatDateTime(Util.parseDateTime(result.old.startDate, IndicoDateTimeFormats.Default), 705 IndicoDateTimeFormats.Ordinal); 706 707 if (result.old.sessionId) { 708 // block was inside session slot 709 delete data[oldDay]['s' + result.old.sessionId + 'l' + result.old.sessionSlotId].entries[result.old.id]; 710 } else { 711 // block was in top level 712 delete data[oldDay][result.old.id]; 713 } 714 715 if(result.slotEntry){ 716 // block moves inside session slot 717 data[result.day][result.slotEntry.id].entries[result.id] = result.entry; 718 // updates the time of the session if it has to be extended 719 data[result.day][result.slotEntry.id].startDate.time = result.slotEntry.startDate.time; 720 data[result.day][result.slotEntry.id].endDate.time = result.slotEntry.endDate.time; 721 } else { 722 // block moves to top level 723 data[result.day][result.id]=result.entry; 724 } 725 }); 726 }, 727 696 728 /* 697 729 * … … 846 878 this.contextInfo.isPoster?null:this.fitInnerTimetableLink, 847 879 customLinks); 848 return Html.div({}, this.warningArea, Html.div('clearfix', this.menu, this.infoBox)); 880 881 var tt_hour_tip = $('<div id="tt_hour_tip"/>').hide().append($('<img/>', {src: imageSrc(Indico.SystemIcons.tt_time), 882 title:"Add one hour"})) 883 884 return $('<div/>').append(this.warningArea.dom, $('<div class="clearfix"/>'). 885 append(this.menu.dom, this.infoBox.dom, tt_hour_tip)); 849 886 }, 850 887 … … 1101 1138 _updateEntry: function(result, oldEntryId, updateCycle) { 1102 1139 1140 var self = this; 1103 1141 var data = this.getData(); 1104 1142 … … 1140 1178 } 1141 1179 1180 var dfr = $.Deferred(); 1181 $('body').one('timetable_redraw', function() { 1182 $('body').trigger('timetable_update', self); 1183 dfr.resolve(); 1184 }); 1142 1185 this.timetableDrawer.redraw(); 1186 return dfr.promise(); 1143 1187 }, 1144 1188 … … 1182 1226 1183 1227 this.timetableDrawer.redraw(); 1184 }, 1185 1186 _updateMovedEntry: function(result, oldEntryId) { 1187 this._updateEntry(result, oldEntryId, function(data){ 1188 if (exists(result.slotEntry)) { 1189 // move into a session slot 1190 data[result.day][result.slotEntry.id].entries[result.id] = result.entry; 1191 // updates the time of the session if it has to be extended 1192 data[result.day][result.slotEntry.id].startDate.time = result.slotEntry.startDate.time; 1193 data[result.day][result.slotEntry.id].endDate.time = result.slotEntry.endDate.time; 1194 } else { 1195 data[result.day][result.id] = result.entry; 1196 } 1197 }); 1228 $('body').trigger('timetable_update', this); 1229 1198 1230 }, 1199 1231 … … 1270 1302 _updateEntry: function(result, oldEntryId, updateCycle) { 1271 1303 1304 var self = this; 1272 1305 var slot = this.contextInfo; 1273 1306 var data = this.getData(); … … 1307 1340 } 1308 1341 1342 var dfr = $.Deferred(); 1343 $('body').one('timetable_redraw', function() { 1344 $('body').trigger('timetable_update', self); 1345 dfr.resolve(); 1346 }); 1309 1347 this.timetableDrawer.redraw(); 1310 1311 }, 1312 1313 _updateMovedEntry: function(result, oldEntryId) { 1314 this._updateEntry(result, oldEntryId, function(data){ 1315 if(exists(result.slotEntry)){ 1316 // from slot to slot 1317 data[result.day][result.slotEntry.id].entries[result.id] = result.entry; 1318 // updates the time of the session if it has to be extended 1319 data[result.day][result.slotEntry.id].startDate.time = result.slotEntry.startDate.time; 1320 data[result.day][result.slotEntry.id].endDate.time = result.slotEntry.endDate.time; 1321 } else { 1322 // from slot to top level 1323 data[result.day][result.id]=result.entry; 1324 } 1325 }); 1348 return dfr.promise(); 1326 1349 }, 1327 1350 … … 1364 1387 } 1365 1388 1389 var dfr = $.Deferred(); 1390 $('body').bind('timetable_redraw', function() { 1391 dfr.resolve(); 1392 }); 1366 1393 this.timetableDrawer.redraw(); 1394 return dfr.promise(); 1367 1395 }, 1368 1396 … … 1398 1426 this.ManagementTimeTable(data, contextInfo, eventInfo, width, wrappingElement, detailLevel, customLinks); 1399 1427 var managementActions = new IntervalTimeTableManagementActions(this, eventInfo, contextInfo, isSessionTimetable); 1400 this.IntervalTimeTableMixin(parent, width, wrappingElement, managementActions );1428 this.IntervalTimeTableMixin(parent, width, wrappingElement, managementActions, 'proportional'); 1401 1429 1402 1430 this.canvas = Html.div({}); … … 1405 1433 this.setData = IntervalTimeTableMixin.prototype.setData; 1406 1434 this.getById = IntervalTimeTableMixin.prototype.getById; 1435 this.postDraw = IntervalTimeTableMixin.prototype.postDraw; 1407 1436 1408 1437 }); -
indico/htdocs/js/indico/Timetable/Draw.js
r791f15 r06b76b 27 27 openPopup: function(event) { 28 28 var self = this; 29 30 //All elements currently being dragged31 /* We don't want to trigger the popup32 if something is being dragged by the mouse */33 var draggingElements = $('.ui-draggable-dragging');34 35 // If popup alredy shown do nothing36 if (self.popupActive || self.materialMenuOpen ||37 (draggingElements.length > 0)) {38 39 return;40 }41 42 29 self.popupActive = true; 43 30 self.div.dom.style.cursor = 'default'; … … 81 68 var self = this; 82 69 83 this.materialMenuOpen = false;70 this.materialMenuOpen = false; 84 71 85 72 var button = Html.div('timetableBlockMaterial'); … … 230 217 }; 231 218 232 this.block = Html.div({style: 233 { 234 position: 'absolute', 235 top: pixels(this.topPos), 236 height: pixels(this.height), 237 backgroundColor: this.printableVersion ? 'white' : this.eventData.color, 238 color: this.printableVersion ? 'black' : this.eventData.textColor, 239 borderColor: this.printableVersion ? 'black' : '', 240 left: pixels(this.leftPos), 241 width: pixels(this.width-3), 242 borderBottomStyle: this.blockData.unfinished?'dashed':'' 243 }, 244 className: 'timetableBlock ' + classTable[this.eventData.entryType] 245 }, this._blockDescription() 246 ); 247 248 self.makeDraggable(self.block, self.eventData); 249 self.makeResizable(self.block, self.eventData); 250 251 //When you drop something on a session timeBlock. 252 if(this.eventData.entryType == 'Session') { 253 self.makeMoveDroppable(self.block, self.eventData); 254 } 219 $(this.block.dom).css({ 220 position: 'absolute', 221 top: pixels(this.topPos), 222 height: pixels(this.height), 223 'background-color': this.printableVersion ? 'white' : this.eventData.color, 224 color: this.printableVersion ? 'black' : this.eventData.textColor, 225 'border-color': this.printableVersion ? 'black' : '', 226 left: pixels(this.leftPos), 227 width: pixels(this.width-3), 228 'border-bottom-style': this.blockData.unfinished?'dashed':'' 229 }); 230 231 $(this.block.dom).addClass('timetableBlock ' + 232 classTable[this.eventData.entryType]); 233 234 this.block.set(this._blockDescription()); 255 235 256 236 // This is a special case, when users shows contribution details it doesn't … … 279 259 if (!self.printableVersion) { 280 260 $(this.block.dom).click(function(e) { 281 self.openPopup(e); 261 if (!self.timetable.getTimetableDrawer().eventsDisabled) { 262 $(this).trigger('tt_block.balloon', e); 263 } 282 264 }); 283 265 highlightWithMouse(this.div, this.block); … … 287 269 }, 288 270 289 makeResizable: function(block, eventData) { 290 var self = this; 291 var originalHeight = $(block.dom).height(); 292 $(block.dom).data('originalheight', originalHeight); 293 var currentEndHour = null; 294 var currentStartHour = null; 295 296 var resizable = $(block.dom).resizable({ 297 containment: $('#timetableDiv'), 298 maxWidth: $(block.dom).width(), 299 minWidth: $(block.dom).width(), 300 301 resize: function(event, ui) { 302 //Array of the form [hour] = '..position().top' (relative to timetable) 303 var hourLines = self.timetable.timetableDrawer.hourLinesArray; 304 var mouseTop = event.pageY; 305 306 var curBestDiff = Number.MAX_VALUE; 307 var curHour = null; 308 var diff = null; 309 310 //This loop extracts the hour you're resizing on. 311 //"The older for loop" is much faster than jQuery by the way 312 for(i in hourLines) { 313 if(hourLines[i] != undefined) { 314 315 // If you pull the resize "edge" where there is 316 // no hourLine div 317 if(!($("#hourLine_"+i).length > 0)) { 318 return; 319 } 320 321 diff = (mouseTop - $("#hourLine_"+i).offset().top); 322 if((diff > 0) && (diff < curBestDiff)) { 323 curBestDiff = diff; 324 curHour = i; 325 } 326 } 327 } 328 329 //returns array, with array[0] = ending hour, array[1] = ending minute (rounded to closest 5-divisible) 330 var gridTime = self.timetable.getTimetableDrawer().fetchTimeDragOnHour($(block.dom), $("#hourLine_"+curHour), curHour, "end"); 331 if(gridTime != null) { 332 currentStartHour = gridTime[0]; 333 currentEndHour = gridTime[1]; 334 } 335 return; 336 }, 337 stop: function(event, ui) { 338 $('.dragTip').hide(); 339 self.timetable.getTimetableDrawer().releaseResizeOnHour(currentStartHour, currentEndHour, eventData, block); 340 } 341 }); 342 }, 343 344 makeDraggable: function(block, eventData) { 345 var self = this; 346 347 var originalWidth = $(block.dom).width(); 348 var originalHeight = $(block.dom).height(); 349 350 /* Resize timeblock if nedeed */ 351 var maxCol = self.timetable.getTimetableDrawer().maxCol; 352 var newWidth = (Math.round($('#timetableDiv').width()/(maxCol))); 353 354 var heightThreshold = 450; 355 var heightChange = (originalHeight > heightThreshold); 356 var newHeight = (heightChange) ? heightThreshold : originalHeight; 357 358 var widthChange = (!(newWidth == originalWidth)); 359 360 var draggable = $(block.dom).draggable({ 361 //Center the mouse in the middle of the block while dragging 362 cursorAt: { 363 left: ((newWidth == undefined) ? 0 : Math.round(newWidth/2)), 364 top: Math.round(newHeight/2) }, 365 containment: $('#timetableDiv'), 366 revert: 'invalid', 367 start: function() { 368 /* Resize timeblock if nedeed */ 369 maxCol = self.timetable.getTimetableDrawer().maxCol; 370 newWidth = (maxCol > 1) ? Math.round($('#timetableDiv').width()/(maxCol)) : originalWidth; 371 372 $(block.dom).width(newWidth); 373 $(block.dom).height(newHeight); 374 375 //(fulhack) Ugly hack [Begin] on jQuery to make the changed width come in to effect while dragging 376 $(this).data('draggable').helperProportions.width = newWidth; 377 $(this).data('draggable').helperProportions.height = newHeight; 378 $(this).data('draggable')._setContainment(); 379 //Ugly hack [End] 380 381 self.timetable.getTimetableDrawer().createDragToolTip(); 382 383 var pos = $(block.dom).position(); 384 draggable.data('initialPosition', pos); 385 }, 386 stop: function() { 387 //reset original width 388 if(widthChange || heightChange) { 389 $(block.dom).animate({ 390 width: originalWidth, 391 height: originalHeight 392 }); 393 } 394 $('.dragTip').remove(); 395 }, 396 drag: function(event) { 397 }}); 398 399 draggable.data('blockInfo', block); 400 draggable.data('eventData', eventData); 401 }, 402 403 /* This is the function that take care of time block drops 404 ON a session */ 405 makeMoveDroppable: function(block, eventData) { 406 var self = this; 407 408 function isSession(ui) { 409 return ($(ui.draggable).hasClass("timetableSession")); 410 } 411 412 function isTouchingWall(ui) { 413 var ret = (($(ui.draggable).position().left == 0) 414 || ($(ui.draggable).position().left == 415 ($('#timetableDiv').width()-$(ui.draggable).width()))); 416 return ret; 417 }; 418 419 $(block.dom).droppable({ 420 drop: function( event, ui ) { 421 $('.dragTip').remove(); 422 423 //If a session is dropped on top do nothing. 424 if(isSession(ui)) { 425 return; 426 } 427 428 /* If the dragged block dropped to the left most side, 429 * or the right most side (touches left/right wall) 430 * AND.. 431 * the drop is handled by the drop-on-session-handler (since we're inside here now...) 432 * THEN 433 * handle it as a normal "HourLine drop". */ 434 435 if(isTouchingWall(ui)) { 436 $('.ui-droppable').droppable('enable'); 437 var ttDrawer = self.timetable.getTimetableDrawer(); 438 ttDrawer.releaseDragOnHour(ui, ttDrawer.curStartHour, ttDrawer.curStartMinute); 439 return; 440 } 441 442 var blockInfo = $(ui.draggable).data('blockInfo'); 443 var blockEventData = $(ui.draggable).data('eventData'); 444 445 var moveEntryDialog = new MoveEntryDialog( 446 self.managementActions, 447 self.timetable, 448 eventData.entryType, 449 eventData.sessionId, 450 eventData.sessionSlotId, 451 timetable.currentDay, 452 eventData.scheduleEntryId, 453 eventData.conferenceId, 454 eventData.startDate.date); 455 456 var chosenValue = eventData.sessionId + ':' + eventData.sessionSlotId; 457 458 var initialPosition = $(ui.draggable).data('initialPosition'); 459 460 //Store Undo data 461 // TODO - not functioning at the moment 462 //self.timetable.getTimetableDrawer().enableUndo("drop", blockEventData); 463 464 moveEntryDialog.handleBlockMove(blockEventData, chosenValue); 465 466 // Non-instanced call, which fails on self.slotId inside the indicoRequest, inside moveEntryDialog(...) 467 /* MoveEntryDialog.prototype.handleBlockMove.call(self, blockEventData, 468 chosenValue, self.managementActions); */ 469 470 return; 471 }, 472 greedy: true, 473 tolerance: 'intersect', 474 activate: function() { 475 $(block.dom).css('border', '2px solid green'); 476 }, 477 deactivate: function() { 478 $(block.dom).css('border', ''); 479 }, 480 over: function(event, ui) { 481 /* If you touch the wall while also 482 * over a session - show that session with the style of 483 * "not current drop target" 484 * 485 */ 486 function(event) { 487 if(isTouchingWall(ui)) { 488 $('.ui-droppable').droppable('enable'); 489 } 490 }; 491 492 if(isSession(ui) || isTouchingWall(ui)) { 493 return; 494 } 495 496 $('.dragTip').hide(); 497 $('.ui-droppable').not(this).droppable('disable'); 498 }, 499 out: function(event, ui) { 500 if(isSession(ui)) { 501 return; 502 } 503 $('.dragTip').show(); 504 $('.ui-droppable').not(this).droppable('enable'); 505 }, 506 }); 507 }, 271 _postDraw: function() { 272 }, 508 273 509 274 postDraw: function(hook) { … … 585 350 586 351 // If content height <= div height then nothing needs to be done 587 if (contentHeight() <= parentDivHeight) { 588 return; 352 if (contentHeight() > parentDivHeight) { 353 // Try to remove the location info, and set title font weight to non bold, 354 // if this works, then we're done. Otherwise, start to truncate the title as well. 355 if (this.timeDiv.dom.style.display == 'none') { 356 this.locationDiv.dom.style.display = 'none'; 357 } 358 359 if (contentHeight() > parentDivHeight) { 360 // Calculates the the width of title, presenters and possible arrows 361 var topContentWidth = function() { 362 var width = 2 * self.margin; 363 if(self.titleDiv) 364 width += self.titleDiv.dom.offsetWidth; 365 if(self.presentersDiv) 366 width += self.presentersDiv.dom.offsetWidth; 367 368 self._postDraw() 369 return width; 370 } 371 372 // Truncate title based on a ratio: div height / content height 373 title = this.truncateTitle(Math.ceil(title.length * ((parentDivHeight) / contentHeight())), title); 374 this.titleDiv.set(title); 375 //String will be shorten by the value of 'step' 376 var step = 2; 377 //Truncating the title since it can be displayed in a single line 378 // title !== "..." avoids the endless loop 379 while (title !== "..." && contentHeight() > parentDivHeight && topContentWidth() > parentDivWidth * 0.8) { 380 title = this.truncateTitle(-step, title); 381 this.titleDiv.set(title); 382 } 383 } 589 384 } 590 385 591 // Try to remove the location info, and set title font weight to non bold, 592 // if this works, then we're done. Otherwise, start to truncate the title as well. 593 if (this.timeDiv.dom.style.display == 'none') { 594 this.locationDiv.dom.style.display = 'none'; 595 } 596 597 if (contentHeight() <= parentDivHeight) { 598 return; 599 } 600 601 //Calculates the the width of title, presenters and possible arrows 602 var topContentWidth = function() { 603 var width = 2 * self.margin; 604 if(self.titleDiv) 605 width += self.titleDiv.dom.offsetWidth; 606 if(self.presentersDiv) 607 width += self.presentersDiv.dom.offsetWidth; 608 609 return width; 610 } 611 612 // Truncate title based on a ratio: div height / content height 613 title = this.truncateTitle(Math.ceil(title.length * ((parentDivHeight) / contentHeight())), title); 614 this.titleDiv.set(title); 615 //String will be shorten by the value of 'step' 616 var step = 2; 617 //Truncating the title since it can be displayed in a single line 618 // title !== "..." avoids the endless loop 619 while (title !== "..." && contentHeight() > parentDivHeight && topContentWidth() > parentDivWidth * 0.8) { 620 title = this.truncateTitle(-step, title); 621 this.titleDiv.set(title); 622 } 623 386 this._postDraw(); 387 return null; 624 388 }, 625 389 createPileEffect: function() { … … 643 407 this.block.dom.style.color = textColor; 644 408 } 409 645 410 }, 646 411 function(timetable, eventData, blockData, compactMode, printableVersion, detailLevel){ 647 648 412 this.TimetableBlockBase(timetable); 649 413 this.compactMode = compactMode; … … 654 418 this.detailLevel = detailLevel; 655 419 this.arrows = Html.span({}); 420 this.block = Html.div({}); 421 422 var self = this; 423 $(this.block.dom).bind('tt_block.balloon', function(event, originalEvent){ 424 if (!self.popupActive) { 425 self.openPopup(originalEvent); 426 } 427 }) 656 428 } 657 429 ); … … 747 519 }); 748 520 749 type("TimetableBlockManagementMixin", [],521 type("TimetableBlockManagementMixin", ["DragAndDropBlockMixin"], 750 522 { 751 523 _drawPopup: function() { … … 803 575 Html.div({className: "ttentryArrowsBackground"}), 804 576 Html.div({className: "ttentryArrows"}, arrowUp, arrowDown)); 577 this.DragAndDropBlockMixin(); 805 578 }); 806 579 … … 821 594 822 595 this._getRightSideDecorators = TimetableBlockManagementMixin.prototype._getRightSideDecorators; 823 596 this._postDraw = TimetableBlockManagementMixin.prototype._postDraw; 824 597 }); 825 598 … … 854 627 855 628 this._getRightSideDecorators = TimetableBlockManagementMixin.prototype._getRightSideDecorators; 856 629 this._postDraw = TimetableBlockManagementMixin.prototype._postDraw; 857 630 }); 858 631 … … 1586 1359 ); 1587 1360 1588 type("TimetableDrawer", ["IWidget" ],1361 type("TimetableDrawer", ["IWidget", "DroppableTimetableMixin"], 1589 1362 { 1590 1363 … … 1597 1370 1598 1371 _drawGrid: function(scale) { 1599 var scaleDiv = Html.div({style: { 1600 position:'relative', 1601 top: pixels(TimetableDefaults.topMargin) 1602 }}); 1372 1373 var scaleDiv = Html.div({ 1374 id: 'timetable_grid', 1375 style: { 1376 position:'relative', 1377 top: pixels(TimetableDefaults.topMargin), 1378 }}); 1603 1379 1604 1380 last = scale[scale.length-1][0]; … … 1614 1390 top: pixels(px), 1615 1391 width: pixels(this.width), 1616 height: hour==last?' 20px':scale[n+1][1]-px,1392 height: hour==last?'0px':scale[n+1][1]-px, 1617 1393 borderTop: '1px dotted red', 1618 1394 fontSize: '11px'}})); … … 1620 1396 } 1621 1397 1622 var hourLineDiv = Html.div({id: 'hourLine_'+parseInt(hour), className: 'hourLine', style: 1623 { position: 'absolute', 1624 top: pixels(px), 1625 width: pixels(this.width), 1626 height: hour==last?'20px':scale[n+1][1]-px, 1627 borderTop: '1px solid #E8E8E8', 1628 fontSize: '11px'}}, zeropad(hour)+':00'); 1629 this._makeHourLineDroppable(hourLineDiv, parseInt(hour)); 1630 1631 this.hourLinesArray[hour] = px; 1632 1633 scaleDiv.append(hourLineDiv); 1398 var hourLineDiv = Html.div({id: 'hourLine_' + parseInt(hour), className: 'hourLine', style: 1399 { top: pixels(px), 1400 width: pixels(this.width), 1401 height: hour == last ? '20px' : scale[n + 1][1] - px} 1402 }, zeropad(hour) + ':00'); 1403 1404 this.make_droppable($(hourLineDiv.dom), parseInt(hour)); 1405 1406 scaleDiv.append(hourLineDiv); 1634 1407 } 1635 1408 return Html.div({}, this.layoutChooser.get().getHeader(this.width), scaleDiv); 1636 1409 }, 1637 1638 1639 createDragToolTip: function() {1640 /*A dragging "tooltip" line that follows wherever a timeblock1641 * is being dragged and displays the current start time1642 * at that current dragging position. */1643 $('#timetableDiv').append($('<div class="dragTip"></div>'));1644 },1645 1646 1647 _calculateRelativeMinuteOffset: function(position, hour) {1648 //If the current hour does not have an hourLine div1649 if(($("#hourLine_"+hour).position() == null)) {1650 return null;1651 }1652 1653 var hourTop = $("#hourLine_"+hour).position().top;1654 var hourHeight = $("#hourLine_"+hour).height();1655 1656 var offsetHeight = (position - hourTop);1657 1658 var minute = Math.floor((offsetHeight/hourHeight) * 59);1659 return ((minute > 60) || (minute < 0))? null : minute;1660 },1661 1662 _makeHourLineDroppable: function(hourDiv, hour) {1663 var self = this;1664 1665 var checkpoints = self.layoutChooser.get().checkpoints;1666 1667 ///* Just a small function to pick out smallest + largest value...1668 var maxMinExtract = function(operator, list) {1669 1670 var significantValue = (operator == "min") ? (Number.MAX_VALUE) : null;1671 _(keys(list)).each(function(x) {1672 //We're actually only interested in the value x for these checkpoints1673 if(operator == "max") {1674 significantValue = (x > significantValue) ? x : significantValue;1675 } else if(operator == "min") {1676 significantValue = (x < significantValue) ? x : significantValue;1677 }1678 });1679 return significantValue;1680 };1681 1682 //Extract the hours from the strings of the form: HHMMSS1683 var dayStartHour = parseInt(new String(maxMinExtract("min", checkpoints)).substring(0,2));1684 var dayEndHour = parseInt(new String(maxMinExtract("max", checkpoints)).substring(0,2));1685 1686 self.dayEndHour = (dayEndHour == 24) ? 00 : dayEndHour;1687 self.dayStartHour = dayStartHour;1688 1689 var isDisallowedTime = function(ui, hourCompare) {1690 /* IF its outside the timetable div topside OR before day-start-hour OR1691 * past midnight, when the day ends prior to 00:00 */1692 return ($(ui.draggable).offset().top < $(hourDiv.dom).offset().top)1693 || (hourCompare < dayStartHour) || ((dayEndHour == 0) && (hourCompare > 0));1694 };1695 1696 //"unique" name for each drag-handler per hourLine1697 var thisDragSpaceName = ("drag."+hour);1698 1699 //These variables are used below1700 var startHour = null;1701 var startMinute = null;1702 1703 $(hourDiv.dom).droppable({1704 drop: function(event, ui) {1705 if(isDisallowedTime(ui, startHour)) {1706 self.revertBlockPos(ui.draggable);1707 return;1708 }1709 1710 self.releaseDragOnHour(ui, startHour, startMinute);1711 },1712 tolerance: 'touch',1713 over: function(event, ui) {1714 $(ui.draggable).bind(thisDragSpaceName, function(newEvent, newUi) {1715 if(isDisallowedTime(ui, hour)) {1716 return;1717 }1718 1719 var gridTime = self.fetchTimeDragOnHour(ui.draggable, hourDiv.dom, hour, "start");1720 1721 //null means that the drag is not allowed1722 if((gridTime == null)) {1723 return;1724 }1725 startHour = gridTime[0];1726 startMinute = gridTime[1];1727 self.curStartHour = startHour;1728 self.curStartMinute = startMinute;1729 1730 });1731 },1732 out: function(event, ui) {1733 if(thisDragSpaceName != null) {1734 $(ui.draggable).unbind(thisDragSpaceName);1735 }1736 $('.dragTip').hide();1737 }1738 });1739 },1740 1741 /* This function determines what hour + minute the time block1742 * should start at for the current dragging pixel position in the timetable.1743 * This function is used by over:, in _makeHourLineDroppable1744 * Args:1745 * ui is the same one that drop(ui,events) is using.1746 * hour = the current "hourLineDiv" being dragged upon1747 *1748 * significantEdge = start or end, whichever is being used to measure with1749 * (start = dragging, end = resizing..)1750 *1751 * Returns an array, where array[0] = startHour, array[1] = startMinute1752 * */1753 fetchTimeDragOnHour: function(draggingBlock, hourDiv, hour, significantEdge) {1754 var self = this;1755 1756 var setToolTipPos = function(newTop) {1757 //Sets the drag-tooltip at the current dragging/resizing position1758 $('.dragTip').offset({1759 left: $('.dragTip').offset().left,1760 top: newTop1761 });1762 };1763 1764 var dragTipTop = null;1765 try {1766 //If we're DRAGGING, and the dragTip is already created...1767 dragTipTop = $(draggingBlock).offset().top;1768 } catch (Exception) {1769 dragTipTop = 0;1770 dragTipTop = $(draggingBlock).offset().top;1771 setToolTipPos(dragTipTop);1772 }1773 1774 //Top left Position of the current hourLine div1775 var hourPos = $(hourDiv).position();1776 1777 var blockPosTop = $(draggingBlock).position().top;1778 var blockHeight = $(draggingBlock).height();1779 var hourLowerLeftCorner = (hourPos.top+$(hourDiv).height());1780 var hourTopLeftCorner = (hourPos.top);1781 1782 //Difference of time block and hour block in height1783 var diffBlockTopLine = blockPosTop - hourTopLeftCorner;1784 1785 var startHour = hour;1786 var startMinute = self._calculateRelativeMinuteOffset(blockPosTop, startHour);1787 1788 var endHour = hour;1789 1790 var blockEnd = (blockPosTop+blockHeight);1791 endMinute = self._calculateRelativeMinuteOffset(blockEnd, endHour);1792 1793 if(!($('.dragTip').length > 0)) {1794 self.timetable.getTimetableDrawer().createDragToolTip();1795 }1796 1797 var gridTime = null;1798 //significantEdge is set by the caller of this whole function1799 // It represents the significant edge to measure with of a time block1800 //That is, if youre resizing, then it will be "end"1801 //Dragging --> "start"1802 if(significantEdge == "start") {1803 setToolTipPos($(draggingBlock).offset().top);1804 //Returns closest 5-minute-divisible, hour and minute in an array1805 gridTime = self.round5(startHour, startMinute);1806 } else if(significantEdge == "end") {1807 setToolTipPos($(draggingBlock).offset().top+blockHeight);1808 gridTime = self.round5(startHour, endMinute);1809 }1810 1811 if(gridTime == null) {1812 return null;1813 }1814 1815 if($('.dragTip').length > 0) {1816 $('.dragTip').show();1817 $('.dragTip').html(gridTime[0]+":"+gridTime[1]);1818 }1819 1820 return gridTime;1821 },1822 1823 enableUndo: function(undoLabel, currentEventData, shifted) {1824 var undoArrayInfo = new Array();1825 undoArrayInfo[0] = undoLabel;1826 1827 //Copying original values before they get modified1828 undoArrayInfo[1] = currentEventData.startDate.date;1829 undoArrayInfo[2] = currentEventData.startDate.time;1830 undoArrayInfo[3] = currentEventData.endDate.date;1831 undoArrayInfo[4] = currentEventData.endDate.time;1832 undoArrayInfo[5] = currentEventData.duration;1833 undoArrayInfo[6] = currentEventData.entryType;1834 undoArrayInfo[7] = currentEventData.conferenceId;1835 1836 //If shifting entries was enabled1837 undoArrayInfo[8] = shifted;1838 //Also keep a reference to the soon-to-be modified eventData1839 undoArrayInfo[9] = currentEventData;1840 $(window).data('undo', undoArrayInfo);1841 this.drawUndoDiv();1842 },1843 1844 undoLastAction: function() {1845 var self = this;1846 var undoArrayInfo = $(window).data('undo');1847 var undoLabel = undoArrayInfo[0];1848 1849 //[**] Fetch stored values for undo1850 1851 //String of the form "HH:MM:SS"1852 var startDate = new Object();1853 startDate.date = undoArrayInfo[1];1854 startDate.time = undoArrayInfo[2];1855 1856 var endDate = new Object();1857 endDate.date = undoArrayInfo[3];1858 endDate.time = undoArrayInfo[4];1859 1860 var duration = undoArrayInfo[5];1861 var entryType = undoArrayInfo[6];1862 var conferenceId = undoArrayInfo[7];1863 1864 var shifted = undoArrayInfo[8];1865 1866 var currentEventData = undoArrayInfo[9];1867 1868 //[**] end1869 1870 /* conferenceId and entryType is cleared it seems at some point when1871 * running editEntryStartEndDate on the original... hmm...1872 * - so here the values are just re-assigned from the original (stored PRIOR to calling editEntrySt...) */1873 currentEventData.entryType = entryType;1874 currentEventData.conferenceId = conferenceId;1875 1876 var startDT = new Date((Util.dateTimeIndicoToJS(startDate)).getTime());1877 var endDT = new Date((Util.dateTimeIndicoToJS(endDate)).getTime());1878 1879 if((undoLabel == "placementChange") || (undoLabel == "resize")) {1880 self.managementActions.editEntryStartEndDate(Util.formatDateTime(startDT, IndicoDateTimeFormats.Server),1881 Util.formatDateTime(endDT, IndicoDateTimeFormats.Server), currentEventData, $(window).data('shiftIsPressed'));1882 } else if(undoLabel == "drop") {1883 // Here goes code to handle drop undo1884 // However I didnt have time to find a reasonable way1885 1886 // Something in the right direction below (debug/test)1887 /*1888 var moveEntryDiag = new MoveEntryDialog(1889 self.managementActions,1890 self.timetable,1891 currentEventData.entryType,1892 currentEventData.sessionId,1893 currentEventData.sessionSlotId,1894 self.timetable.currentDay,1895 currentEventData.scheduleEntryId,1896 currentEventData.conferenceId,1897 currentEventData.startDate.date);1898 1899 var chosenValue = currentEventData.sessionId;1900 moveEntryDiag.handleBlockMove(currentEventData, chosenValue+":0", self.managementActions);1901 */1902 }1903 1904 $(window).data('undo', undefined);1905 $('#undoDiv').remove();1906 return;1907 },1908 1909 /* A "button" that appears after an action is performed */1910 drawUndoDiv: function() {1911 //If it isnt drawn already1912 if(!($('#undoDiv').length > 0)) {1913 var self = this;1914 var undoLink = Html.a({}, "Undo last action");1915 undoLink.observeClick(1916 function(e) {1917 self.undoLastAction();1918 });1919 1920 var undoDiv =1921 Html.div({1922 id: 'undoDiv',1923 className: 'undoDiv',1924 style: {1925 padding: '5px',1926 background: '#FFF',1927 border: '3px solid black',1928 position: 'fixed',1929 bottom: '0px',1930 left: '50%'1931 }}, undoLink);1932 $('#timetableDiv').append(undoDiv.dom);1933 }1934 },1935 1936 /* The function to execute when a drop occurs ON an hour.1937 * The argument ui is the same one that drop(ui,events) is using.1938 *1939 * startHour is the hour where it is being dropped (0 to 23)1940 * startMinute is the minute where it is being dropped, a 5-divisible in the range 0-551941 * startHour and startMinute is determined by fetchTimeDragOnHour(..)1942 *1943 * This function is used by drop:, in _makeHourLineDroppable1944 */1945 releaseDragOnHour: function(ui, startHour, startMinute) {1946 var self = this;1947 $('.dragTip').remove();1948 1949 if((startMinute == null) || (startHour == 00)) {1950 self.revertBlockPos(ui.draggable);1951 return false;1952 }1953 1954 //originalEventData is used for the undo functionality1955 var eventData = $(ui.draggable).data('eventData');1956 1957 //Store Undo data1958 self.enableUndo("placementChange", eventData, $(window).data('shiftIsPressed'));1959 1960 eventData.startDate.time = startHour+":"+startMinute+":00";1961 1962 var startDT = Util.dateTimeIndicoToJS(eventData.startDate);1963 var endDT = new Date(startDT.getTime() + eventData.duration*60000);1964 1965 //If it doesnt end on the same day, revert drag1966 if(endDT.getDay() > startDT.getDay()) {1967 self.revertBlockPos(ui.draggable);1968 return false;1969 }1970 1971 self.managementActions.editEntryStartEndDate(Util.formatDateTime(eventData.startDate, IndicoDateTimeFormats.Server),1972 Util.formatDateTime(endDT, IndicoDateTimeFormats.Server), eventData, $(window).data('shiftIsPressed'));1973 1974 return true;1975 },1976 1977 releaseResizeOnHour: function(endHour, endMinute, eventData, block) {1978 var self = this;1979 self.enableUndo("resize", eventData);1980 1981 eventData.endDate.time = endHour+":"+endMinute+":00";1982 var endDT = Util.dateTimeIndicoToJS(eventData.endDate);1983 var startDT = Util.dateTimeIndicoToJS(eventData.startDate);1984 1985 // HERE GOES CODE TO LIMIT RESIZE FOR THE CURRENT DAY ONLY1986 //If it doesnt end on the same day, revert drag1987 /*1988 if((self.dayEndHour == 0) && (false)) {1989 self.revertBlockHeight(block);1990 return false;1991 }1992 */1993 1994 self.managementActions.editEntryStartEndDate(Util.formatDateTime(eventData.startDate, IndicoDateTimeFormats.Server),1995 Util.formatDateTime(endDT, IndicoDateTimeFormats.Server),1996 eventData, false);1997 1998 //Store Undo-data1999 return true;2000 },2001 2002 revertBlockHeight: function(block) {2003 $(block.dom).animate({2004 height: $(block.dom).data('originalheight')2005 });2006 },2007 2008 /* Returns a draggable to its initial position */2009 revertBlockPos: function(draggable) {2010 var initPos = $(draggable).data('initialPosition');2011 2012 $(draggable).animate({2013 left: initPos.left,2014 top: initPos.top2015 });2016 $('.dragTip').remove();2017 },2018 2019 round5: function (hour, minute) {2020 2021 //Rounds the number to the closest 5-divisible,..2022 //Also appends padding to the number, such that 0 = 00, 1 = 01...2023 closestFive = (minute % 5) >= 2.5 ? parseInt(minute / 5) * 5 + 5 : parseInt(minute / 5) * 5;2024 var newHour = ((minute > 55) && (closestFive == 60)) ? (hour+1) : hour;2025 var timeArray = new Array();2026 if(newHour > 23) {2027 return null;2028 }2029 timeArray[0] = zeropad(newHour);2030 timeArray[1] = zeropad((closestFive == 60) ? 00 : closestFive);2031 return timeArray;2032 },2033 2034 /* Since javascripts mod (%) function/operator can't2035 * properly handle negative numbers here's a real one */2036 properModulus: function(num, modn) {2037 return ((num%modn)+modn)%modn;2038 },2039 1410 2040 1411 _drawWholeDayBlocks: function(data, blocks) { … … 2081 1452 } 2082 1453 }); 2083 2084 self.blocks = []1454 this.blocks = [] 1455 this._blockMap = {} 2085 1456 2086 1457 each(blocks, function(blockData) { … … 2119 1490 2120 1491 if (self.managementMode) { 2121 2122 1492 block = new TimetableBlockNormalManagement(self.timetable, eventData, blockData, compactMode, self.printableVersion, self.detail.get(), self.managementActions); 1493 2123 1494 } else { 2124 1495 block = new TimetableBlockNormalDisplay(self.timetable, eventData, blockData, compactMode, self.printableVersion, self.detail.get()); 2125 1496 } 2126 1497 blockDiv.append(block.draw(leftPos, width)); 1498 self._blockMap[blockData.id] = block.block.dom; 2127 1499 self.blocks.push(block); 2128 1500 }); … … 2132 1504 2133 1505 setLayout: function(layout) { 1506 this.layout.set(layout); 2134 1507 this.layoutChooser.set(layout); 2135 1508 }, 2136 1509 2137 1510 redraw: function(day) { 1511 2138 1512 if (this.preventRedraw) { 2139 1513 return; … … 2158 1532 this.wrappingElement.setStyle('height', pixels(height + (this.printableVersion ? 0 : 100))); // +100 to have margin for the tabs 2159 1533 2160 var grid = this._drawGrid(dayData[1]); 1534 this.grid.length = 0; 1535 $.merge(this.grid, dayData[1]) 1536 1537 var gridElems = this._drawGrid(this.grid); 2161 1538 var blocks = this._drawBlocks(dayFiltered, dayData[2], dayData[3]); 2162 1539 var wholeDayBlocks = this._drawWholeDayBlocks(dayFiltered, dayData[4]); 2163 1540 2164 1541 // Only do if not all days are drawn 2165 this.canvas.set([wholeDayBlocks, Html.div({style: {position: 'relative'}}, grid , blocks)]);1542 this.canvas.set([wholeDayBlocks, Html.div({style: {position: 'relative'}}, gridElems, blocks)]); 2166 1543 var totalHeight = height + wholeDayBlocks.dom.offsetHeight; 2167 1544 … … 2169 1546 2170 1547 this.postDraw(); 1548 1549 $('body').trigger('timetable_redraw', this); 2171 1550 2172 1551 return totalHeight; … … 2349 1728 this.loadingIndicator.dom.style.visibility = 'visible'; 2350 1729 setTimeout(function() { 1730 // call redraw function 2351 1731 funcToCall.call(self, arg); 1732 $('body').trigger('timetable_ready', self.timetable); 2352 1733 self.setLoading(false); 2353 1734 }, 100); … … 2362 1743 this.data = data; 2363 1744 this.redraw(); 1745 }, 1746 toggleEvents: function(value) { 1747 if (value === undefined) { 1748 this.eventsDisabled = !this.eventsDisabled; 1749 } else { 1750 this.eventsDisabled = !value; 1751 } 2364 1752 } 1753 2365 1754 }, 2366 1755 function(timetable, width, wrappingElement, detailLevel, extraButtons, loadingIndicator, managementMode, managementActions, defaultLayout) { 2367 1756 2368 2369 1757 var self = this; 2370 1758 2371 this.hourLinesArray = new Array(); 2372 1759 this.grid = []; 2373 1760 this.wrappingElement = wrappingElement; 2374 this.canvas = Html.div({ });1761 this.canvas = Html.div({'id': 'timetable_canvas'}); 2375 1762 this.filterList = new WatchList(); 2376 1763 this.data = timetable.data; … … 2404 1791 // default detail level is 'session' 2405 1792 this.detail.set(any(detailLevel, 'session')); 2406 1793 this.eventsDisabled = false; 2407 1794 2408 1795 var filterState = map(TimetableDefaults.filters, … … 2428 1815 } 2429 1816 }); 1817 1818 this.DroppableTimetableMixin(); 2430 1819 }); 2431 1820 … … 2497 1886 }, 2498 1887 2499 postDraw: function() {2500 2501 },2502 2503 1888 setData: function(data, day, isPoster) { 2504 1889 this.isPoster = isPoster; … … 2507 1892 this.setLayout('poster'); 2508 1893 } else { 2509 this.setLayout( 'compact');1894 this.setLayout(this.layout.get()); 2510 1895 } 2511 1896 this.TimetableDrawer.prototype.setData.call(this, data); 2512 1897 } 2513 1898 }, 2514 function(data, canvas, width, wrappingElement, extraButtons, loadingIndicator, managementMode, managementActions) {2515 this.TimetableDrawer(data, canvas, width, wrappingElement, 'session', extraButtons, loadingIndicator, managementMode, managementActions, data.isPoster?'poster':null);1899 function(data, width, wrappingElement, extraButtons, loadingIndicator, managementMode, managementActions, layout) { 1900 this.TimetableDrawer(data, width, wrappingElement, 'session', extraButtons, loadingIndicator, managementMode, managementActions, data.isPoster?'poster':'proportional'); 2516 1901 this.wrappingElement = data.parentTimetable.timetableDrawer.wrappingElement; 2517 1902 -
indico/htdocs/js/indico/Timetable/Layout.js
r791f15 r06b76b 216 216 type("IncrementalLayoutManager", ["TimetableLayoutManager"], 217 217 { 218 name: 'incremental', 218 219 drawDay: function(data, detailLevel, startTime, endTime) { 219 220 var self = this; … … 265 266 var hEnd; 266 267 268 // add hour before start 269 if (startingHour > 0) { 270 for (var min = 0; min < 60 ; min += TimetableDefaults.resolution) { 271 self.processTimeBlock(startingHour - 1, startingHour, (startingHour - 1) * 60, min, algData); 272 } 273 } 274 267 275 for (var minutes = 0; minutes < ((endingHour + 1 - startingHour) * 60); minutes += TimetableDefaults.resolution) { 268 269 276 // current block is [minutes, minutes + 5] 270 277 var startMin = (startingHour * 60 + minutes); … … 274 281 275 282 self.processTimeBlock(hStart, hEnd, startMin, minutes, algData); 276 277 283 } 278 284 279 285 if ($L(ks).indexOf('nextday') !== null) { 280 286 self.processTimeBlock('nextday', 'nextday', (startingHour * 60 + minutes), minutes, algData); 281 } else {287 } else if (endMin/60 < 25){ 282 288 // add last hour + 1 to the grid 289 // (only if the next hour is not after midnight) 283 290 algData.grid.push([(endMin/60) % 24, algData.topPx]); 284 291 } … … 292 299 counter++; 293 300 }); 294 295 301 return [algData.topPx, algData.grid, algData.blocks, algData.groups, algData.wholeDayBlocks]; 296 302 … … 302 308 { 303 309 310 name: 'compact', 304 311 processTimeBlock: function(hStart, hEnd, startMin, minutes, algData) { 305 312 var self = this; … … 411 418 type("ProportionalLayoutManager", ["IncrementalLayoutManager"], 412 419 { 413 420 name: 'proportional', 414 421 processTimeBlock: function(hStart, hEnd, startMin, minutes, algData) { 415 422 var self = this; … … 458 465 }); 459 466 460 if (minutes % 60 === 0) { 461 algData.grid.push([startMin/60%24, algData.topPx]); 467 var hour = startMin / 60; 468 if (minutes % 60 === 0 && hour <= 24) { 469 algData.grid.push([hour % 24, algData.topPx]); 462 470 } 463 471 … … 581 589 } 582 590 }); 583 -
indico/htdocs/js/indico/Timetable/Loader.js
rae6179 r06b76b 1 1 include(ScriptRoot + "indico/Timetable/Layout.js"); 2 include(ScriptRoot + "indico/Timetable/DragAndDrop.js"); 3 include(ScriptRoot + "indico/Timetable/Undo.js"); 2 4 include(ScriptRoot + "indico/Timetable/Draw.js"); 3 5 include(ScriptRoot + "indico/Timetable/Management.js"); -
indico/htdocs/js/indico/Timetable/Management.js
r791f15 r06b76b 1 type("TimetableManagementActions", [ ], {1 type("TimetableManagementActions", ["UndoMixin"], { 2 2 methods: { 3 3 'SessionSlot': { … … 144 144 * Edit start and end date. date format has to be dd/mm/yy mm:hh 145 145 */ 146 editEntryStartEndDate: function(startDate, endDate, eventData, reschedule ) {146 editEntryStartEndDate: function(startDate, endDate, eventData, reschedule, undo) { 147 147 var self = this; 148 148 var info = new WatchObject(); … … 171 171 } 172 172 173 //Displays a "loading ..." div at the righthand bottom side 174 var killProgress = IndicoUI.Dialogs.Util.blockMoveProgress(); 173 var dfr = $.Deferred(); 174 175 //Displays a "loading ..." div at the righthand bottom side 176 var killProgress = IndicoUI.Dialogs.Util.ttStatusInfo($T('saving...')); 175 177 176 178 indicoRequest(this.methods[type].modifyStartEndDate, info, function(result, error){ 177 killProgress(); 179 if (!undo) { 180 killProgress(); 181 } 182 178 183 if (error) { 179 184 IndicoUtil.errorReport(error); 180 } 181 else { 185 dfr.reject(error); 186 if (undo) { 187 killProgress(); 188 } 189 } else { 182 190 // Depending on whether 'reschedule' was selected or not, 183 191 // update the whole day or just one entry 184 192 193 if(undo) { 194 self.enableUndo(undo, {eventData: eventData, 195 shifted: reschedule}); 196 } 197 185 198 if (reschedule) { 186 self.timetable._updateDay(result); 199 self.timetable._updateDay(result).done(function() { 200 dfr.resolve(); 201 }); 187 202 } else { 188 self.timetable._updateEntry(result, result.id); 203 self.timetable._updateEntry(result, result.id).done(function() { 204 dfr.resolve(); 205 }); 189 206 } 190 207 } 191 208 }); 209 210 return dfr.promise(); 211 }, 212 213 /* Takes care of moving a contribution/timeblock to another session/timetable. 214 * This goes for both "drag and drop" as well as the regular "MoveEntry Dialog clicking"*/ 215 moveToSession: function(eventData, value, undo, keep_time) { 216 var self = this; 217 218 // if nothing has been selected yet 219 if (value === null || value === undefined) { 220 return false; 221 } 222 223 // Displays a "loading ..." div at the righthand bottom side 224 var killProgress = IndicoUI.Dialogs.Util.ttStatusInfo($T("saving...")); 225 var dfr = $.Deferred(); 226 227 indicoRequest(this.methods[this.isSessionTimetable ? 'SessionEntry' : 'Event'].moveEntry, { 228 value : value, 229 conference : eventData.conferenceId, 230 scheduleEntryId : eventData.scheduleEntryId, 231 sessionId : eventData.sessionId, 232 sessionSlotId : eventData.sessionSlotId, 233 keepTime: keep_time || false 234 }, function(result, error) { 235 236 if (!undo) { 237 killProgress(); 238 } 239 240 if (error) { 241 IndicoUtil.errorReport(error); 242 dfr.reject(error); 243 } else { 244 if (undo) { 245 self.enableUndo(undo, {'eventData': eventData, 246 'entry': result.entry}, null); 247 self.drawUndoDiv(); 248 } 249 // change json and repaint timetable 250 self.timetable._updateMovedEntry(result, result.old.id).done(function() { 251 dfr.resolve() 252 }); 253 }}); 254 return dfr.promise(); 192 255 }, 193 256 … … 587 650 this, 588 651 this.timetable, 589 eventData.entryType, 590 eventData.sessionId, 591 eventData.sessionSlotId, 592 timetable.currentDay, 593 eventData.scheduleEntryId, 594 eventData.conferenceId, 595 eventData.startDate.date ); 652 eventData, 653 timetable.currentDay); 596 654 moveEntryDiag.open(); 597 655 },
Note: See TracChangeset
for help on using the changeset viewer.
