Do not use JS to initialize the schedule

- Only use JS for the drag&drop functionality and to the set/alter the time and rooms of the EventSchedule object.

- Introduce has_many :events, through: :event_schedules association to get unscheduled event easily
This commit is contained in:
Ana 2016-07-31 18:41:27 +02:00
parent 71dab6b79c
commit a394293500
12 changed files with 66 additions and 125 deletions

View file

@ -1,76 +1,14 @@
var conference; // Should be initialize in Schedule.loadEvents
var schedule_id; // Should be initialize in Schedule.loadEvents
var conference; // Should be initialize in Schedule.initialize
var schedule_id; // Should be initialize in Schedule.initialize
var Schedule = {
loadEvents: function(conference_param, schedule_id_param) {
initialize: function(conference_param, schedule_id_param) {
conference = conference_param;
schedule_id = schedule_id_param;
var url = '/admin/conference/' + conference + '/program/events';
var callback = function(data) {
$.each(data, function(key, val) {
Schedule.newEvent(val);
});
};
$.getJSON(url, callback);
},
newEvent: function(vars) {
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 +'\');" 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) {
var e = $("#" + element);
var unscheduled = $(".unscheduled-events");
var url = '/admin/conference/' + conference + '/schedule/' + schedule_id;
var params = {
event: e.attr("guid"),
@ -92,7 +30,7 @@ var Schedule = {
dataType : 'json'
});
},
save: function (event_id, room_id, date, time) {
add: function (event_id, room_id, date, time) {
var url = '/admin/conference/' + conference + '/schedule/' + schedule_id;
var params = {
event: event_id,
@ -116,6 +54,27 @@ var Schedule = {
};
$(document).ready( function() {
// hide the remove button for unscheduled events
$('.unscheduled-events .schedule-event-delete-button').hide();
// set events as draggable
$('.schedule-event').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
});
// set room cells as droppable
$('.schedule-room-slot').droppable({
accept: '.schedule-event',
tolerance: "pointer",
@ -128,7 +87,7 @@ $(document).ready( function() {
$(ui.draggable).css("left", 0);
$(ui.draggable).css("top", 0);
$(this).css("background-color", "#ffffff");
Schedule.save(myId, myRoom, myDate, myTime);
Schedule.add(myId, myRoom, myDate, myTime);
},
over: function(event, ui) {
$(this).css("background-color", "#009ED8");

View file

@ -21,6 +21,9 @@ module Admin
def show
@schedule_id = params[:id].to_i
schedule = Schedule.find(@schedule_id)
@event_schedules = schedule.event_schedules
@unscheduled_events = @program.events.confirmed - schedule.events
@selected_schedule_id = @conference.program.selected_schedule.try(:id)
@dates = @conference.start_date..@conference.end_date
@rooms = (@venue && @venue.rooms.any?) ? @venue.rooms : [Room.new(name: 'No Rooms!', size: 0)]
@ -44,7 +47,7 @@ module Admin
error_message = "Could not find event GUID: #{params[:event]}"
end
event_schedule = event.event_schedule(params[:schedule])
event_schedule = event.event_schedules.find_by(schedule_id: params[:schedule])
if params[:date] == 'none'
event_schedule.destroy if event_schedule.present?

View file

@ -6,11 +6,11 @@ class SchedulesController < ApplicationController
def show
@rooms = @conference.venue.rooms if @conference.venue
unless @program.selected_schedule.present? && @program.events.scheduled(@program.selected_schedule.id).any?
schedules = @program.selected_event_schedules
unless schedules
redirect_to events_conference_schedule_path(@conference.short_title)
end
schedules = @program.selected_event_schedules
@events_xml = schedules.map(&:event).group_by{ |event| event.scheduled_start_time.to_date } if schedules
@dates = @conference.start_date..@conference.end_date
@step_minutes = EventType::LENGTH_STEP.minutes
@ -32,7 +32,11 @@ class SchedulesController < ApplicationController
@events_schedules = @program.selected_event_schedules
@events_schedules = [] unless @events_schedules
@unscheduled_events = @program.events.unscheduled(@program.selected_schedule.id)
@unscheduled_events = if @program.selected_schedule
@program.events.confirmed - @program.selected_schedule.events
else
@program.events.confirmed
end
day = @conference.current_conference_day
@tag = day.strftime('%Y-%m-%d') if day

View file

@ -78,15 +78,6 @@ class Event < ActiveRecord::Base
selected_event_schedule.present?
end
##
# 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?(schedule_id)
state == 'confirmed' && !event_schedule(schedule_id).present?
end
def registration_possible?
return false unless require_registration && state == 'confirmed'
return true if max_attendees.nil?
@ -138,15 +129,6 @@ class Event < ActiveRecord::Base
end
end
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
end
def transition_possible?(transition)
self.class.state_machine.events_for(current_state).include?(transition)
end
@ -263,11 +245,6 @@ class Event < ActiveRecord::Base
selected_event_schedule.try(:start_time)
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
# returns the event_schedule for this event and for the selected_schedule
def selected_event_schedule
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id))

View file

@ -32,10 +32,6 @@ class Program < ActiveRecord::Base
joins(:event_schedules).where('event_schedules.schedule_id = ?', schedule_id)
end
def unscheduled(schedule_id)
select{ |e| e.unscheduled?(schedule_id) }
end
def highlights
where(state: :confirmed, is_highlight: true)
end

View file

@ -1,4 +1,5 @@
class Schedule < ActiveRecord::Base
belongs_to :program
has_many :event_schedules, dependent: :destroy
has_many :events, through: :event_schedules
end

View file

@ -34,7 +34,6 @@ class EventSerializer < ActiveModel::Serializer
end
end
# FIXME: duplicated logic from Event#as_json
def length
object.event_type.try(:length) || EventType::LENGTH_STEP
end

View file

@ -1,13 +1,20 @@
- date_event_schedules = @event_schedules.select{ |e| e.start_time.to_date.eql? date }
.row
- @rooms.each do |room|
.col-md-2.col-xs-6
.room-name
- room_date_event_schedules = date_event_schedules.select{ |e| e.room == room }
= 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}", |
- minutes = (15 * (slot % 4) == 0) ? '00' : 15 * (slot % 4)
- time = "#{hour}:#{minutes}"
.schedule-room-slot{ id: "schedule-room-#{room.guid}-#{hour}-#{minutes}", |
"room-guid" => room.guid, |
hour: "#{hour}:#{time}", |
hour: time, |
date: date}
= "#{hour}:#{time}"
.div
= time
- event_schedules = room_date_event_schedules.select{ |e| (e.start_time.hour.to_s + e.start_time.strftime(':%M')).eql? time }
- if event_schedules.any?
= render partial: 'event', locals: { event: event_schedules.first.event }

View file

@ -0,0 +1,13 @@
- cells_length = event.event_type.length / EventType::LENGTH_STEP
/ this height fits the room cells
- height = (cells_length * 58) - 23
/ subtracting the padding before calculate the number of lines
- lines = (height - 7) / 23
- color = event.track.try(:color).present? ? event.track.try(:color) : 'FFFFFF'
.schedule-event{ style: "height: #{height}px; background-color: #{color}; color: #{contrast_color(color)}", |
id: "event-#{event.guid}", |
guid: event.guid, |
length: cells_length }
.schedule-event-text{ style: "-webkit-line-clamp: #{lines}; height: #{lines * 23}px;"}
%span.schedule-event-delete-button{ onclick: "Schedule.remove(\'event-#{event.guid}\');" } X
= event.title

View file

@ -17,6 +17,8 @@
.h4
Unscheduled events
.unscheduled-events
- @unscheduled_events.each do |e|
= render partial: 'event', locals: { event: e }
.col-md-10
%ul.nav.nav-tabs
- @dates.each do |date|
@ -30,5 +32,5 @@
:javascript
$(document).ready( function() {
Schedule.loadEvents("#{@conference.short_title}", "#{@schedule_id}");
Schedule.initialize("#{@conference.short_title}", "#{@schedule_id}");
});

View file

@ -259,27 +259,6 @@ describe Event do
end
end
describe '#as_json' do
it 'adds the event\'s track_color, track_text_color and length' do
create(:event_schedule, event: event)
event.track = create(:track, color: '#efefef')
json_hash = event.as_json
expect(json_hash[:track_color]).to eq('#EFEFEF')
expect(json_hash[:track_text_color]).to eq('black')
expect(json_hash[:length]).to eq(30)
end
it 'uses correct default values for track_color, track_text_color and length' do
event.event_type = nil
json_hash = event.as_json
expect(json_hash[:track_color]).to eq('#FFFFFF')
expect(json_hash[:track_text_color]).to eq('black')
expect(json_hash[:length]).to eq(15)
end
end
describe '#transition_possible?(transition)' do
shared_examples 'transition_possible?(transition)' do |state, transition, expected|
it "returns #{expected} for #{transition} transition, when the event is #{state}}" do

View file

@ -5,5 +5,6 @@ describe Schedule do
describe 'association' do
it { should belong_to(:program) }
it { should have_many(:event_schedules).dependent(:destroy) }
it { should have_many(:events).through(:event_schedules) }
end
end