mirror of
https://github.com/openSUSE/osem.git
synced 2026-08-15 12:44:03 +00:00
Integrate the schedule in the admin interface
Integrate the schedule in the admin interface while adapting it to the new associations and models.
This commit is contained in:
parent
e7a30302ff
commit
dfd64a4510
32 changed files with 291 additions and 10074 deletions
|
|
@ -13,6 +13,7 @@
|
|||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require jquery.mobile.custom.min
|
||||
//= require jquery-ui.min
|
||||
//= require waypoints/jquery.waypoints
|
||||
//= require dataTables/jquery.dataTables
|
||||
//= require dataTables/bootstrap/3/jquery.dataTables.bootstrap
|
||||
|
|
|
|||
13
app/assets/javascripts/jquery-ui.min.js
vendored
Normal file
13
app/assets/javascripts/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -14,4 +14,5 @@
|
|||
*= require bootstrap-datetimepicker
|
||||
*= require leaflet
|
||||
*= require bootstrap3-switch
|
||||
*= require jquery-ui.min
|
||||
*/
|
||||
|
|
|
|||
7
app/assets/stylesheets/jquery-ui.min.css
vendored
Normal file
7
app/assets/stylesheets/jquery-ui.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -1,3 +1,52 @@
|
|||
|
||||
.room-name{
|
||||
font-weight: bold;
|
||||
padding:10px;
|
||||
margin-top: 30px;
|
||||
border: 1px solid #848484;
|
||||
background-color: #E6E6E6;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
height: 40px;
|
||||
line-height: 25px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.schedule-room-slot{
|
||||
padding: 2px 5px;
|
||||
border: 1px solid #848484;
|
||||
height: 58px;
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.schedule-event{
|
||||
padding: 7px;
|
||||
border: 2px solid #151515;
|
||||
position:relative;
|
||||
z-index:1;
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
.schedule-event-text{
|
||||
display: -webkit-box;
|
||||
text-overflow: ellipsis;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 23px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.schedule-event-delete-button {
|
||||
font-weight:bold;
|
||||
cursor: pointer;
|
||||
padding: 0px 3px;
|
||||
border: 1px solid grey;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#schedule td.event {
|
||||
background-image: linear-gradient(bottom, rgb(247,250,242) 24%, rgb(194,232,190) 97%, rgb(194,232,190) 100%);
|
||||
background-image: -o-linear-gradient(bottom, rgb(247,250,242) 24%, rgb(194,232,190) 97%, rgb(194,232,190) 100%);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ module Admin
|
|||
load_resource :venue, through: :conference, singleton: true
|
||||
|
||||
skip_before_filter :verify_authenticity_token, only: [:update]
|
||||
layout 'schedule'
|
||||
|
||||
def show
|
||||
authorize! :update, @program.events.new
|
||||
event = @program.events.new
|
||||
authorize! :update, event
|
||||
event.destroy
|
||||
if @conference.nil?
|
||||
redirect_to admin_conference_index_path
|
||||
return
|
||||
|
|
@ -21,6 +22,13 @@ module Admin
|
|||
else
|
||||
@rooms = [ Room.new(name: 'No Rooms!', size: 0) ]
|
||||
end
|
||||
# if there is not selected schedule we create it
|
||||
unless @program.selected_schedule.present?
|
||||
schedule = @program.schedules.create
|
||||
@program.selected_schedule = schedule.id
|
||||
@program.save!
|
||||
end
|
||||
@schedule_id = @program.selected_schedule
|
||||
end
|
||||
|
||||
def update
|
||||
|
|
@ -31,14 +39,17 @@ module Admin
|
|||
error_message = "Could not find event GUID: #{params[:event]}"
|
||||
end
|
||||
|
||||
event_schedule = event.event_schedule(params[:schedule])
|
||||
|
||||
if params[:date] == 'none'
|
||||
event.start_time = nil
|
||||
event.room = nil
|
||||
event.save!
|
||||
event_schedule.destroy if event_schedule.present?
|
||||
render json: { 'status' => 'ok' }
|
||||
return
|
||||
end
|
||||
|
||||
event_schedule = event.event_schedules.create(schedule_id: params[:schedule]) unless event_schedule.present?
|
||||
room = Room.where(guid: room_params).first
|
||||
|
||||
if room.nil?
|
||||
error_message = "Could not find room GUID: #{params[:room]}"
|
||||
end
|
||||
|
|
@ -48,7 +59,7 @@ module Admin
|
|||
return
|
||||
end
|
||||
|
||||
event.room = room
|
||||
event_schedule.room = room
|
||||
time = "#{params[:date]} #{params[:time]}"
|
||||
|
||||
Rails.logger.debug("Loading #{time}")
|
||||
|
|
@ -57,8 +68,8 @@ module Admin
|
|||
# zone = ActiveSupport::TimeZone::new(@conference.timezone)
|
||||
# start_time = DateTime.strptime(time + zone.formatted_offset, "%Y-%m-%d %k:%M %Z")
|
||||
start_time = DateTime.strptime(time, '%Y-%m-%d %k:%M')
|
||||
event.start_time = start_time
|
||||
event.save!
|
||||
event_schedule.start_time = start_time
|
||||
event_schedule.save!
|
||||
render json: { 'status' => 'ok' }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -79,11 +79,12 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
|
||||
##
|
||||
# Checkes if the event has a start_time and a room for the selected one if there is any.
|
||||
# Checkes if the event has a start_time and a room for the given schedule
|
||||
# (given by its id) or for the selected one if there is any.
|
||||
# ====Returns
|
||||
# * +true+ or +false+
|
||||
def unscheduled?
|
||||
state == 'confirmed' && (!selected_event_schedule.try(:start_time).present? || !selected_event_schedule.try(:room).present?)
|
||||
def unscheduled?(schedule_id)
|
||||
state == 'confirmed' && (!event_schedule(schedule_id).try(:start_time).present? || !event_schedule(schedule_id).try(:room).present?)
|
||||
end
|
||||
|
||||
def registration_possible?
|
||||
|
|
@ -137,11 +138,10 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def as_json(options)
|
||||
json = super(options)
|
||||
|
||||
json[:room_guid] = scheduled_room.try(:guid)
|
||||
def as_json(options={})
|
||||
json = super({ include: { event_schedules: { methods: [:room_guid] } } }.merge(options))
|
||||
json[:track_color] = track.try(:color) || '#FFFFFF'
|
||||
json[:track_text_color] = ApplicationController.helpers.contrast_color(json[:track_color])
|
||||
json[:length] = event_type.try(:length) || EventType::LENGTH_STEP
|
||||
|
||||
json
|
||||
|
|
@ -277,6 +277,11 @@ class Event < ActiveRecord::Base
|
|||
room.events.where(start_time: start_time).where.not(id: id)
|
||||
end
|
||||
|
||||
# returns the event_schedule for this event and the schedule given in case that it exists
|
||||
def event_schedule(schedule_id)
|
||||
event_schedules.find_by(schedule_id: schedule_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# returns the event_schedule for this event and for the selected_schedule
|
||||
|
|
|
|||
|
|
@ -2,4 +2,8 @@ class EventSchedule < ActiveRecord::Base
|
|||
belongs_to :schedule
|
||||
belongs_to :event
|
||||
belongs_to :room
|
||||
|
||||
def room_guid
|
||||
room.try(:guid)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ class Program < ActiveRecord::Base
|
|||
joins(:event_schedules).where('event_schedules.schedule_id = ? AND event_schedules.start_time IS NOT NULL AND event_schedules.room_id IS NOT NULL', schedule_id)
|
||||
end
|
||||
|
||||
def unscheduled
|
||||
select(&:unscheduled?)
|
||||
def unscheduled(schedule_id=nil)
|
||||
select{ |e| e.unscheduled?(schedule_id) }
|
||||
end
|
||||
|
||||
def highlights
|
||||
|
|
|
|||
|
|
@ -1,23 +1,13 @@
|
|||
.schedule-time-column
|
||||
.schedule-time-column-header
|
||||
= Time
|
||||
- (9..18).each do |hour|
|
||||
.schedule-time-slot
|
||||
= "#{hour}:00"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:15"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:30"
|
||||
.schedule-time-slot
|
||||
= "#{hour}:45"
|
||||
|
||||
- @rooms.each do |room|
|
||||
.schedule-room-column{:id => "schedule-room-#{room.guid}", "room-guid" => room.guid}
|
||||
.schedule-room-column-header
|
||||
= room.name
|
||||
= "(#{room.size} people)"
|
||||
- (9..18).each do |hour|
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-0", "room-guid" => room.guid, "hour" => "#{hour}:00"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-15", "room-guid" => room.guid, "hour" => "#{hour}:15"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-30", "room-guid" => room.guid, "hour" => "#{hour}:30"}
|
||||
.schedule-room-slot{:id => "schedule-room-#{room.guid}-#{hour}-45", "room-guid" => room.guid, "hour" => "#{hour}:45"}
|
||||
.row
|
||||
- @rooms.each do |room|
|
||||
.col-md-2.col-xs-6
|
||||
.room-name
|
||||
= room.name
|
||||
- (9*4..18*4).each do |slot|
|
||||
- hour = slot / 4
|
||||
- time = (15 * (slot % 4) == 0) ? '00' : 15 * (slot % 4)
|
||||
.schedule-room-slot{ id: "schedule-room-#{room.guid}-#{hour}-#{time}", |
|
||||
"room-guid" => room.guid, |
|
||||
hour: "#{hour}:#{time}", |
|
||||
date: date}
|
||||
= "#{hour}:#{time}"
|
||||
|
|
|
|||
|
|
@ -1,48 +1,166 @@
|
|||
.schedule-content
|
||||
%h2
|
||||
= "Schedule for #{@conference.title}"
|
||||
#unscheduled.unscheduled
|
||||
.unscheduled-header
|
||||
Unscheduled Events
|
||||
#schedule.schedule
|
||||
.schedule-dates-header
|
||||
%ul#date-tabs
|
||||
- @dates.each do |date|
|
||||
%li.date-selector
|
||||
= link_to "#{date}", "#", id: "#{date}-selector", onclick: "Schedule.changeDay('#{date}')"
|
||||
.schedule-rooms-container
|
||||
= render 'day_tab'
|
||||
.row
|
||||
.col-md-12
|
||||
.page-header
|
||||
%h1 Schedule
|
||||
%p.text-muted
|
||||
Create the schedules for the conference
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
.h4
|
||||
Unscheduled events
|
||||
.unscheduled-events
|
||||
.col-md-10
|
||||
%ul.nav.nav-tabs
|
||||
- @dates.each do |date|
|
||||
%li{ class: "#{ (@dates.first == date) ? 'active' : '' }"}
|
||||
%a{ href: "##{date}" }
|
||||
= date
|
||||
.tab-content
|
||||
- @dates.each do |date|
|
||||
.tab-pane{ class: "#{ (@dates.first == date) ? 'active' : '' }", id: "#{date}" }
|
||||
= render partial: 'day_tab', locals: { date: date }
|
||||
|
||||
|
||||
:javascript
|
||||
$(document).ready( function() {
|
||||
//Schedule.loadDaysAndTracks("#{@conference.short_title}");
|
||||
var conference = "#{@conference.short_title}"
|
||||
Schedule.loadEvents("#{@conference.short_title}", "#{@dates.first}");
|
||||
$('.schedule-room-slot').droppable({
|
||||
accept: '.schedule-event',
|
||||
tolerance: "pointer",
|
||||
drop: function(event, ui) {
|
||||
$(ui.draggable).appendTo(this);
|
||||
var myId = $(ui.draggable).attr("guid");
|
||||
var myRoom = $(this).attr("room-guid")
|
||||
var myDate = $(this).attr("date");
|
||||
var myTime = $(this).attr("hour");
|
||||
var length = $(ui.draggable).attr("length");
|
||||
$(ui.draggable).css("left", 0);
|
||||
$(ui.draggable).css("top", 0);
|
||||
$(this).css("background-color", "#ffffff");
|
||||
|
||||
// 15 minute slots on the schedule are 30px,
|
||||
// thus the magic multiplier here
|
||||
$(ui.draggable).height(length * 2 - 7);
|
||||
$(ui.draggable).width($(this).width() - 10);
|
||||
Schedule.save(conference, myId, myRoom, myDate, myTime);
|
||||
},
|
||||
over: function(event, ui) {
|
||||
$(this).css("background-color", "#009ED8");
|
||||
},
|
||||
out: function(event, ui) {
|
||||
$(this).css("background-color", "#ffffff");
|
||||
}
|
||||
});
|
||||
});
|
||||
var conference = "#{@conference.short_title}"
|
||||
var schedule_id = "#{@schedule_id}";
|
||||
|
||||
var Schedule = {
|
||||
loadEvents: function(conference_id, start_date) {
|
||||
var url = '/admin/conference/' + conference_id + '/program/events';
|
||||
var callback = function(data) {
|
||||
$.each(data, function(key, val) {
|
||||
Schedule.newEvent(val, conference_id);
|
||||
});
|
||||
};
|
||||
$.getJSON(url, callback);
|
||||
},
|
||||
newEvent: function(vars, conference_id) {
|
||||
var height = (vars["length"] / 15 * 58) - 23; // this height fits the room cells
|
||||
var lines = Math.floor((height - 7) / 23); // subtracting the padding before calculate the number of lines
|
||||
var newEvent = $('<div class="schedule-event">'
|
||||
+ '<div class="schedule-event-text" style="-webkit-line-clamp: '+ lines + '; height: ' + (lines * 23) + 'px;">'
|
||||
+ '<span onclick="Schedule.remove(\'event-' + vars["guid"] + '\', \'' + conference_id +'\');" class="schedule-event-delete-button">X</span>'
|
||||
+ vars["title"] + '</div></div>');
|
||||
newEvent.attr("id", "event-" + vars["guid"]);
|
||||
newEvent.attr("guid", vars["guid"]);
|
||||
newEvent.css("height", height);
|
||||
newEvent.css('background-color',vars["track_color"]);
|
||||
newEvent.css('color',vars["track_text_color"]);
|
||||
var date = "none";
|
||||
var room = "none"
|
||||
var time = "none";
|
||||
for (i = 0; i < vars["event_schedules"].length; i++) {
|
||||
event_schedule = vars["event_schedules"][i];
|
||||
if(event_schedule["schedule_id"] == schedule_id){
|
||||
room = event_schedule["room_guid"];
|
||||
var d = new Date(event_schedule["start_time"]);
|
||||
date = d.getUTCFullYear() + "-"
|
||||
+ ('0' + (d.getUTCMonth() +1)).slice(-2) + '-'
|
||||
+ ('0' + d.getUTCDate()).slice(-2);
|
||||
minutes = d.getUTCMinutes();
|
||||
time = d.getUTCHours() + ':' + (minutes == 0 ? '00' : minutes);
|
||||
console.log("date: " + d);
|
||||
newEvent.attr("room", room);
|
||||
newEvent.attr("date", date);
|
||||
newEvent.attr("hour", time);
|
||||
}
|
||||
}
|
||||
newEvent.draggable({
|
||||
snap: '.schedule-room-slot',
|
||||
revertDuration: 200,
|
||||
revert: function (event, ui) {
|
||||
console.log(event.attr);
|
||||
return !event;
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
this._originalPosition = this._originalPosition || ui.originalPosition;
|
||||
ui.helper.animate( this._originalPosition );
|
||||
},
|
||||
opacity: 0.7,
|
||||
snapMode: "inner",
|
||||
zIndex: 2
|
||||
});
|
||||
if (date == "none" || room == "none") {
|
||||
newEvent.find(".schedule-event-delete-button").hide();
|
||||
$('.unscheduled-events').append(newEvent);
|
||||
} else {
|
||||
var element = "[date='" + date +"'][hour='" + time + "'][room-guid='" + room + "']";
|
||||
$(element).append(newEvent);
|
||||
}
|
||||
},
|
||||
remove: function(element, conference_id) {
|
||||
var e = $("#" + element);
|
||||
var unscheduled = $(".unscheduled-events");
|
||||
|
||||
var url = '/admin/conference/' + conference_id + '/schedule';
|
||||
var params = {
|
||||
event: e.attr("guid"),
|
||||
room: "none",
|
||||
date: "none",
|
||||
time: "none",
|
||||
schedule: schedule_id
|
||||
};
|
||||
var callback = function(data) {
|
||||
console.log(data);
|
||||
e.appendTo(unscheduled);
|
||||
e.find(".schedule-event-delete-button").hide();
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'PUT',
|
||||
data: params,
|
||||
success: callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
},
|
||||
save: function (conference_id, event_id, room_id, date, time) {
|
||||
var url = '/admin/conference/' + conference_id + '/schedule';
|
||||
var params = {
|
||||
event: event_id,
|
||||
room: room_id,
|
||||
date: date,
|
||||
time: time,
|
||||
schedule: schedule_id
|
||||
};
|
||||
var callback = function(data) {
|
||||
console.log(data);
|
||||
$("#event-" + event_id).find(".schedule-event-delete-button").show();
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'PUT',
|
||||
data: params,
|
||||
success: callback,
|
||||
dataType : 'json'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Schedule.loadEvents("#{@conference.short_title}", "#{@dates.first}");
|
||||
|
||||
$(document).ready( function() {
|
||||
$('.schedule-room-slot').droppable({
|
||||
accept: '.schedule-event',
|
||||
tolerance: "pointer",
|
||||
drop: function(event, ui) {
|
||||
$(ui.draggable).appendTo(this);
|
||||
var myId = $(ui.draggable).attr("guid");
|
||||
var myRoom = $(this).attr("room-guid")
|
||||
var myDate = $(this).attr("date");
|
||||
var myTime = $(this).attr("hour");
|
||||
$(ui.draggable).css("left", 0);
|
||||
$(ui.draggable).css("top", 0);
|
||||
$(this).css("background-color", "#ffffff");
|
||||
Schedule.save(conference, myId, myRoom, myDate, myTime);
|
||||
},
|
||||
over: function(event, ui) {
|
||||
$(this).css("background-color", "#009ED8");
|
||||
},
|
||||
out: function(event, ui) {
|
||||
$(this).css("background-color", "#ffffff");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
= link_to 'Difficulty Levels', admin_conference_program_difficulty_levels_path(@conference.short_title)
|
||||
- if can? :update, @conference.program.events.build
|
||||
%li{class: active_nav_li(admin_conference_schedule_path(@conference.short_title))}
|
||||
= link_to 'Schedule', admin_conference_schedule_path(@conference.short_title), target: '_blank'
|
||||
= link_to 'Schedule', admin_conference_schedule_path(@conference.short_title)
|
||||
|
||||
- if can? :update, Registration.new(conference_id: @conference.id)
|
||||
%li{:class=> active_nav_li(admin_conference_registrations_path(@conference.short_title))}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue