diff --git a/Gemfile.lock b/Gemfile.lock index f6fcb33..1ca0cf3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -162,11 +162,11 @@ GEM daemons (1.2.3) database_cleaner (1.5.0) debug_inspector (0.0.2) - delayed_job (4.0.6) + delayed_job (4.1.1) activesupport (>= 3.0, < 5.0) - delayed_job_active_record (4.0.3) - activerecord (>= 3.0, < 5.0) - delayed_job (>= 3.0, < 4.1) + delayed_job_active_record (4.1.0) + activerecord (>= 3.0, < 5) + delayed_job (>= 3.0, < 5) diff-lcs (1.2.5) diffy (3.0.7) docile (1.1.5) @@ -189,16 +189,16 @@ GEM railties (>= 3.2, < 5.0) forgery (0.6.0) formatador (0.2.5) - gdk_pixbuf2 (3.0.3) - glib2 (= 3.0.3) - gdk_pixbuf2 (3.0.3-x86-mingw32) - glib2 (= 3.0.3) + gdk_pixbuf2 (3.0.5) + glib2 (= 3.0.5) + gdk_pixbuf2 (3.0.5-x86-mingw32) + glib2 (= 3.0.5) geocoder (1.2.11) gherkin3 (3.1.1) git-version-bump (0.15.1) - glib2 (3.0.3) + glib2 (3.0.5) pkg-config - glib2 (3.0.3-x86-mingw32) + glib2 (3.0.5-x86-mingw32) cairo (>= 1.12.8) pkg-config globalid (0.3.6) @@ -225,7 +225,7 @@ GEM haml (>= 4.0.6, < 5.0) html2haml (>= 1.0.1) railties (>= 4.0.1) - highline (1.7.5) + highline (1.7.7) html2haml (2.0.0) erubis (~> 2.7.0) haml (~> 4.0.0) @@ -266,7 +266,7 @@ GEM mime-types (2.6.2) mini_magick (4.3.3) mini_portile (0.6.2) - minitest (5.8.0) + minitest (5.8.1) mocha (1.1.0) metaclass (~> 0.0.1) multi_json (1.11.2) @@ -278,7 +278,7 @@ GEM net-ssh (>= 2.6.5) net-sftp (2.1.2) net-ssh (>= 2.6.5) - net-ssh (2.9.2) + net-ssh (3.0.1) net-ssh-gateway (1.2.0) net-ssh (>= 2.6.5) netrc (0.10.3) @@ -296,9 +296,9 @@ GEM jwt (~> 0.1.4) multi_json (~> 1.0) rack (~> 1.2) - pango (3.0.3-x86-mingw32) + pango (3.0.5-x86-mingw32) cairo (>= 1.14.0) - glib2 (= 3.0.3) + glib2 (= 3.0.5) paper_trail (3.0.8) activerecord (>= 3.0, < 5.0) activesupport (>= 3.0, < 5.0) @@ -314,11 +314,11 @@ GEM cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - pry (0.10.1) + pry (0.10.2) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) - pry (0.10.1-x86-mingw32) + pry (0.10.2-x86-mingw32) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) @@ -397,13 +397,13 @@ GEM rspec-mocks (~> 3.3.0) rspec-support (~> 3.3.0) rspec-support (3.3.0) - rsvg2 (3.0.3) + rsvg2 (3.0.5) cairo (>= 1.12.8) - gdk_pixbuf2 (= 3.0.3) - rsvg2 (3.0.3-x86-mingw32) + gdk_pixbuf2 (= 3.0.5) + rsvg2 (3.0.5-x86-mingw32) cairo (>= 1.12.8) - gdk_pixbuf2 (= 3.0.3) - pango (>= 3.0.3) + gdk_pixbuf2 (= 3.0.5) + pango (>= 3.0.5) ruby_parser (3.7.1) sexp_processor (~> 4.1) rubyzip (1.1.7) @@ -411,7 +411,7 @@ GEM capistrano (~> 2.15.4) safe_yaml (1.0.4) sass (3.4.18) - sass-json-vars (0.3.2) + sass-json-vars (0.3.3) sass (>= 3.1) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) @@ -438,8 +438,8 @@ GEM bcrypt (~> 3.1) oauth (~> 0.4, >= 0.4.4) oauth2 (>= 0.8.0) - sprockets (3.3.4) - rack (~> 1.0) + sprockets (3.3.5) + rack (> 1, < 3) sprockets-rails (2.3.3) actionpack (>= 3.0) activesupport (>= 3.0) diff --git a/app/assets/stylesheets/_application.scss b/app/assets/stylesheets/_application.scss index 4b31f79..d38194d 100644 --- a/app/assets/stylesheets/_application.scss +++ b/app/assets/stylesheets/_application.scss @@ -88,7 +88,6 @@ button, &.register { background-color: $colour-4; - //@include _(text-shadow, 0 0 0.15em rgba(0, 0, 0, 0.5)); } form.logout & { @@ -102,6 +101,10 @@ button, #main &.delete { background-color: $colour-4; } + + #main &.secondary { + background-color: $colour-1; + } } a.button { @@ -505,12 +508,16 @@ input { padding: 0 0.25em; font-weight: normal; @include font-family(secondary); - @include _(text-stroke, 0.5px #000) + @include _(text-stroke, 0.5px #000); } .date-labels { float: left; } + + .date-field { + overflow: auto; + } } form { @@ -530,6 +537,10 @@ form { vertical-align: middle; } + &.left { + text-align: left; + } + &.right { text-align: right; @@ -1940,3 +1951,234 @@ html[data-lingua-franca-example="html"] { float: left; } } + +.conferences-edit_schedule { + #main { + .location { + padding-top: 0.25em; + } + .errors { + padding: 0.25em; + background-color: $colour-2; + color: $white; + @include _(text-stroke, 0.5px #000); + } + .conflict-score { + padding: 0.25em; + background-color: $colour-3; + color: #333; + } + .all-workshops, .all-events { + list-style: none; + padding: 0; + + li { + margin: 0.5em; + padding: 0.5em; + border: 1px solid #CCC; + background-color: lighten($colour-1, 35); + @include default-box-shadow(top, 2); + + &.error { + outline: 0.2em solid $colour-2; + outline-offset: -0.2em; + } + } + + h3 { + margin: 0; + } + + .workshop-interest { + color: #888; + text-align: left; + margin: 0.25em 0; + } + + .error-description { + background-color: $colour-2; + color: $white; + padding: 0.5em; + margin-top: 0.5em; + } + + .warnings { + background-color: $colour-3; + color: #333; + padding: 0.5em; + margin-top: 0.5em; + list-style: none; + + li { + padding: 0; + margin: 0; + background-color: transparent; + @include _(box-shadow, none); + } + } + } + .day_parts { + list-style: none; + + h4 { + display: inline-block; + min-width: 12.5em; + margin: 0.25em 0; + } + + select, .select { + float: right; + min-width: 5em; + } + + .select { + padding-left: 0.25em; + } + } + .actions { + margin: 2em; + } + .unsaved { + @include font-family(secondary); + background-color: lighten($colour-3, 25); + margin: 0 5em 2em; + padding: 0.5em; + } + .all-events { + li { + background-color: lighten($colour-5, 35); + + &.meal { + background-color: lighten($colour-3, 25); + } + } + + h3 { + margin-bottom: 0.5em; + } + } + } +} + +.programme { + + .schedule { + width: auto; + margin: 0; + min-width: 100%; + @include _(box-shadow, none); + table-layout: fixed; + border-spacing: 0.25em; + border-collapse: separate; + + td { + position: relative; + vertical-align: middle; + + .title { + text-align: center; + @include font-family(secondary); + color: #666; + } + + + &.previewable { + cursor: pointer; + + &:hover { + @include default-box-shadow(top, 2); + } + } + + &.workshop { + background-color: lighten($colour-1, 35); + border: 0.25em solid $colour-1; + + .preview { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + + @include after { + display: none; + } + } + } + + &.event { + background-color: lighten($colour-5, 35); + border: 0.25em solid $colour-5; + } + + &.meal { + background-color: lighten($colour-3, 25); + border: 0.25em solid $colour-3; + } + + &.not-interested { + opacity: 0.5; + } + + .info { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + background-color: $white; + text-align: left; + overflow-y: auto; + @include _(transition, transform 250ms ease-in-out); + @include _(transform-origin, center bottom); + @include _(transform, rotate(180deg) translate3d(0, 0, 0)); + + .close { + float: right; + font-size: 2em; + + @include before { + content: '×'; + padding: 0 0.5em; + } + + @include after { + display: none; + } + } + + h2 { + margin-bottom: 0.5em; + } + } + + &:target .info { + @include _(transform, rotate(0) translate3d(0, 0, 0)); + } + } + } + + .programme-day { + margin-top: 2em; + } + + .programme-day-part { + overflow-x: auto; + } +} + +.select-field { + line-height: 1.75em; + + select { + display: block; + width: 100%; + height: 2.1em; + font-family: inherit; + font-size: 1.5em; + padding: 0.25em; + @include default-box-shadow(top, 1.5, false); + } +} diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index 980120f..6d5e9d3 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -7,7 +7,7 @@ $sidebar-width: rems(19); // $colour-5: #8EA604; $colour-1: #00ADEF; // blue -$colour-2: #DD57EF; // pink +$colour-2: #EF57B4; // #DD57EF; // pink $colour-3: #E6C74B; // yellow $colour-4: #D89E59; // orange $colour-5: #02CA9E; // green diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 94bd7a2..f0c201a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -4,6 +4,8 @@ module ActiveRecord end class ApplicationController < LinguaFrancaApplicationController + include ScheduleHelper + # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception, :except => [:do_confirm] @@ -35,6 +37,21 @@ class ApplicationController < LinguaFrancaApplicationController super end + def home + @workshops = Workshop.where(:conference_id => @conference.id) + + if @conference.workshop_schedule_published + @events = Event.where(:conference_id => @conference.id) + schedule = get_schedule_data + @schedule = schedule[:schedule] + @locations = Hash.new + EventLocation.where(:conference_id => @conference.id).each do |l| + @locations[l.id.to_s] = l + end + @day_parts = @conference.day_parts ? JSON.parse(@conference.day_parts) : {:morning => 0, :afternoon => 13, :evening => 18} + end + end + def policy @is_policy_page = true end diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index 450f87a..fe2a31e 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -2,6 +2,8 @@ require 'geocoder/calculations' require 'rest_client' class ConferencesController < ApplicationController + include ScheduleHelper + before_action :set_conference, only: [:show, :edit, :update, :destroy, :registrations] before_filter :authenticate, only: [:registrations] @@ -890,8 +892,8 @@ class ConferencesController < ApplicationController can_edit = workshop.can_edit?(current_user) do_403 unless can_edit || workshop.can_translate?(current_user, I18n.locale) - workshop.title = params[:title] - workshop.info = params[:info] + workshop.title = params[:title] + workshop.info = params[:info] if can_edit # dont allow translators to edit these fields @@ -1033,6 +1035,269 @@ class ConferencesController < ApplicationController return redirect_to view_workshop_url(@this_conference.slug, params[:workshop_id]) end + def schedule + set_conference + do_404 unless @this_conference.workshop_schedule_published || @this_conference.host?(current_user) + + @events = Event.where(:conference_id => @this_conference.id) + @locations = EventLocation.where(:conference_id => @this_conference.id) + + render 'schedule/show' + end + + def edit_schedule + set_conference + set_conference_registration + do_404 unless @this_conference.host?(current_user) + + @workshops = Workshop.where(:conference_id => @this_conference.id) + @events = Event.where(:conference_id => @this_conference.id) + if session[:workshops] + (0...@workshops.count).each do |i| + id = @workshops[i].id + w = session[:workshops][id.to_s] + if w + @workshops[i].start_time = w[:start_time] + @workshops[i].end_time = w[:end_time] + @workshops[i].event_location_id = w[:event_location_id] + end + end + end + if session[:events] + (0...@events.count).each do |i| + id = @events[i].id + w = session[:events][id.to_s] + if w + @events[i].start_time = w[:start_time] + @events[i].end_time = w[:end_time] + @events[i].event_location_id = w[:event_location_id] + end + end + end + @locations = EventLocation.where(:conference_id => @this_conference.id) + @location_hash = Hash.new + @locations.each do |l| + @location_hash[l.id.to_s] = l + end + + @days = Array.new + start_day = @this_conference.start_date.strftime('%u').to_i + end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400) + + (start_day..end_day).each do |i| + @days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), ((i + 1) - start_day)] + end + + @hours = Array.new + (0..48).each do |i| + hour = (Date.today + (i / 2.0).hours).strftime('%R') + @hours << hour + end + + @event_durations = [['30 mins', 30], ['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120], ['2.5 hours', 150]] + @workshop_durations = [['1 hour', 60], ['1.5 hours', 90], ['2 hours', 120]] + + schedule_data = get_schedule_data + @schedule = schedule_data[:schedule] + @errors = schedule_data[:errors] + @warnings = schedule_data[:warnings] + @conflict_score = schedule_data[:conflict_score] + @error_count = schedule_data[:error_count] + if session[:day_parts] + @day_parts = JSON.parse(session[:day_parts]) + elsif @this_conference.day_parts + @day_parts = JSON.parse(@this_conference.day_parts) + else + @day_parts = {:morning => 0, :afternoon => 13, :evening => 18} + end + @saved = session[:workshops].nil? + + render 'schedule/edit' + end + + def save_schedule + set_conference + do_404 unless @this_conference.host?(current_user) + + @days = Array.new + start_day = @this_conference.start_date.strftime('%u').to_i + end_day = start_day + ((@this_conference.end_date - @this_conference.start_date) / 86400) + + (start_day..end_day).each do |i| + @days << [(@this_conference.start_date + (i - start_day).days).strftime('%a'), i] + end + + @workshops = Workshop.where(:conference_id => @this_conference.id) + @events = Event.where(:conference_id => @this_conference.id) + @locations = EventLocation.where(:conference_id => @this_conference.id) + + do_save = (params[:button] == 'save' || params[:button] == 'publish') + session[:workshops] = do_save ? nil : Hash.new + session[:events] = do_save ? nil : Hash.new + session[:day_parts] = do_save ? nil : Hash.new + + (0...@workshops.count).each do |i| + id = @workshops[i].id.to_s + if params[:workshop_day][id].present? && params[:workshop_hour][id].present? && params[:workshop_duration][id].present? + date = @this_conference.start_date + (params[:workshop_day][id].to_i - 1).days + h = params[:workshop_hour][id].split(':') + date = date.change({hour: h.first, minute: h.last}) + @workshops[i].start_time = date + @workshops[i].end_time = date + (params[:workshop_duration][id].to_i).minutes + else + @workshops[i].start_time = nil + @workshops[i].end_time = nil + end + @workshops[i].event_location_id = params[:workshop_location][id] + if do_save + @workshops[i].save + else + session[:workshops][id] = { + :start_time => @workshops[i].start_time, + :end_time => @workshops[i].end_time, + :end_time => @workshops[i].end_time, + :event_location_id => @workshops[i].event_location_id + } + end + end + + (0...@events.count).each do |i| + id = @events[i].id.to_s + if params[:event_day][id].present? && params[:event_hour][id].present? && params[:event_duration][id].present? + date = @this_conference.start_date + (params[:event_day][id].to_i - 1).days + h = params[:event_hour][id].split(':') + date = date.change({hour: h.first, minute: h.last}) + @events[i].start_time = date + @events[i].end_time = date + (params[:event_duration][id].to_i).minutes + else + @events[i].start_time = nil + @events[i].end_time = nil + end + @events[i].event_location_id = params[:event_location][id] + if do_save + @events[i].save + else + session[:events][id] = { + :start_time => @events[i].start_time, + :end_time => @events[i].end_time, + :end_time => @events[i].end_time, + :event_location_id => @events[i].event_location_id + } + end + end + + if params[:day_parts] + day_parts = {:morning => 0} + params[:day_parts].each do |part, h| + h = h.split(':') + day_parts[part.to_sym] = h[0].to_f + (h[1].to_i > 0 ? 0.5 : 0) + end + if do_save + @this_conference.day_parts = day_parts.to_json + else + session[:day_parts] = day_parts.to_json + end + end + + save_conference = do_save + + if params[:button] == 'publish' + @this_conference.workshop_schedule_published = true + save_conference = true + elsif params[:button] == 'unpublish' + @this_conference.workshop_schedule_published = false + save_conference = true + end + + if save_conference + @this_conference.save + end + + redirect_to edit_schedule_url(@this_conference.slug) + end + + def add_event + set_conference + set_conference_registration + do_404 unless @this_conference.host?(current_user) + + render 'events/edit' + end + + def edit_event + set_conference + set_conference_registration + do_404 unless @this_conference.host?(current_user) + + @event = Event.find(params[:id]) + do_403 unless @event.conference_id == @this_conference.id + + render 'events/edit' + end + + def save_event + set_conference + do_404 unless @this_conference.host?(current_user) + + + if params[:event_id] + event = Event.find(params[:event_id]) + do_403 unless event.conference_id == @this_conference.id + else + event = Event.new(:conference_id => @this_conference.id) + end + + event.title = params[:title] + event.info = params[:info] + event.event_type = params[:event_type] + + event.save + + return redirect_to schedule_url(@this_conference.slug) + end + + def add_location + set_conference + set_conference_registration + do_404 unless @this_conference.host?(current_user) + + render 'event_locations/edit' + end + + def edit_location + set_conference + set_conference_registration + do_404 unless @this_conference.host?(current_user) + + @location = EventLocation.find(params[:id]) + do_403 unless @location.conference_id == @this_conference.id + + @amenities = JSON.parse(@location.amenities || '[]').map &:to_sym + + render 'event_locations/edit' + end + + def save_location + set_conference + do_404 unless @this_conference.host?(current_user) + + + if params[:location_id] + location = EventLocation.find(params[:location_id]) + do_403 unless location.conference_id == @this_conference.id + else + location = EventLocation.new(:conference_id => @this_conference.id) + end + + location.title = params[:title] + location.address = params[:address] + location.amenities = (params[:needs] || {}).keys.to_json + + location.save + + return redirect_to schedule_url(@this_conference.slug) + end + # DELETE /conferences/1 #def destroy # @conference.destroy @@ -1053,6 +1318,7 @@ class ConferencesController < ApplicationController register_path(@this_conference.slug) => 'registration.Registration', workshops_path(@this_conference.slug) => 'registration.Workshops' } + @submenu[schedule_path(@this_conference.slug)] = 'registration.Schedule' if @this_conference.workshop_schedule_published || @is_host if @is_host @submenu[edit_conference_path(@this_conference.slug)] = 'registration.Edit' @submenu[stats_path(@this_conference.slug)] = 'registration.Stats' diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fffecd9..c72001b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,8 @@ require 'redcarpet' module ApplicationHelper + include ScheduleHelper + @@keyQueue = nil @@translationsOnThisPage = nil @@lastTranslation = nil diff --git a/app/helpers/schedule_helper.rb b/app/helpers/schedule_helper.rb new file mode 100644 index 0000000..e3a7d20 --- /dev/null +++ b/app/helpers/schedule_helper.rb @@ -0,0 +1,146 @@ + +module ScheduleHelper + def get_schedule_data + schedule = Hash.new + workshop_errors = Hash.new + workshop_warnings = Hash.new + + all_events = (@workshops + @events) + conflicts = 0 + errors = 0 + + (0...all_events.count).each do |i| + w = all_events[i] + + if w.start_time.present? && w.end_time.present? && w.event_location_id.present? + type = w.is_a?(Workshop) ? :workshop : :event + + hour = w.start_time.strftime('%H').to_i + hour += 0.5 if w.start_time.strftime('%M').to_i > 15 + + end_hour = w.end_time.strftime('%H').to_i + end_hour += 0.5 if w.end_time.strftime('%M').to_i > 15 + + day = w.conference_day + + schedule[day] ||= Hash.new + schedule[day][:locations] ||= Hash.new + schedule[day][:locations][w.event_location_id] ||= Hash.new + + conflict = nil + (hour...end_hour).step(0.5).each do |h| + h = h.to_i if h == h.to_i + if !conflict && schedule[day][:locations][w.event_location_id][h].present? + conflict = schedule[day][:locations][w.event_location_id][h] + end + end + + if conflict.present? + w_conflict = get_workshop(conflict, @workshops, @events) + workshop_errors[(w_conflict.is_a?(Workshop) ? 'w' : 'e') + w_conflict.id.to_s] = "Time conflict with “#{w_conflict.title}”".html_safe + workshop_errors[(w.is_a?(Workshop) ? 'w' : 'e') + w.id.to_s] = "Time conflict with “#{w.title}”".html_safe + errors += 1 if workshop_errors[(w_conflict.is_a?(Workshop) ? 'w' : 'e') + w_conflict.id.to_s].nil? + else + schedule[day][:start_time] = hour if schedule[day][:start_time].nil? || hour < schedule[day][:start_time] + schedule[day][:end_time] = end_hour if schedule[day][:end_time].nil? || end_hour > schedule[day][:end_time] + + schedule[day][:locations][w.event_location_id][hour] = { + :span => w.duration / 60.0, + :type => w.is_a?(Event) ? w.event_type : :workshop + } + schedule[day][:locations][w.event_location_id][hour][:workshop] = i if type == :workshop + schedule[day][:locations][w.event_location_id][hour][:event] = (i - @workshops.count) if type == :event + end + else + workshop_warnings["w#{w.id}"] ||= Array.new + workshop_warnings["w#{w.id}"] << (w.is_a?(Workshop) ? "This workshop is not scheduled" : "This event is not scheduled") + end + end + + schedule.each do |day, day_data| + day_data[:locations].each do |location1, location_data1| + location_data1.each do |time1, data1| + day_data[:locations].each do |location2, location_data2| + location_data2.each do |time2, data2| + if data1[:workshop].present? + if data2[:workshop].present? + unless location1 == location2 && time1 == time2 + if workshop_errors[data1[:workshop]].nil? + w1 = @workshops[data1[:workshop]] + w2 = @workshops[data2[:workshop]] + if time1 == time2 + w1.workshop_facilitators.each do |f| + u = User.find(f.user_id) + if w2.active_facilitator?(u) + errors += 1 if workshop_errors[(w2.is_a?(Workshop) ? 'w' : 'e') + w2.id.to_s].nil? + workshop_errors["w#{w1.id}"] = "This workshop shares facilitators with “#{w2.title}”".html_safe + end + end + connection ||= ActiveRecord::Base.connection + common_interest_count = connection.select_value("SELECT COUNT(w1.user_id) FROM workshop_interests AS w1 JOIN workshop_interests AS w2 ON w2.user_id=w1.user_id WHERE w1.workshop_id=#{w1.id} AND w2.workshop_id=#{w2.id}") + common_interest_count = common_interest_count ? common_interest_count.to_i : 0 + if common_interest_count > 0 + conflicts += common_interest_count + workshop_warnings["w#{w1.id}"] ||= Array.new + workshop_warnings["w#{w1.id}"] << "#{common_interest_count} people are also interested in “#{w2.title}”".html_safe + end + end + end + end + end + end + end + end + end + end + end + + { + :schedule => schedule.sort, + :errors => workshop_errors, + :warnings => workshop_warnings, + :conflict_score => conflicts, + :error_count => errors + } + end + + def get_workshop(workshop, workshops, events) + workshop[:workshop] ? workshops[workshop[:workshop]] : (events[workshop[:event]] || :event) + end + + def workshop_classes(workshop, show_interest) + classes = [workshop.is_a?(Workshop) ? :workshop : workshop.event_type] + if show_interest && workshop.is_a?(Workshop) && current_user && WorkshopInterest.where(:user_id => current_user.id) + if workshop.interested?(current_user) || workshop.facilitator?(current_user) + classes << 'interested' + else + classes << 'not-interested' + end + end + + return classes + end + + def schedule_start_and_end_times(day_part, day_parts, day_schedule) + start_time = [day_parts[day_parts.keys[day_part]], day_schedule[:start_time]].max + end_time = [day_parts[day_parts.keys[day_part + 1]] || 24, day_schedule[:end_time]].min + + min_time = nil + max_time = nil + + day_schedule[:locations].each do |location, location_schedule| + location_schedule.each do |hour, workshop| + t_start = hour + t_end = hour + workshop[:span] + if t_start >= start_time && t_end <= end_time + min_time = [min_time || 24, t_start].min + max_time = [max_time || 0, t_end].max + end + end + end + + return nil unless min_time.present? && max_time.present? + + [min_time || 0, max_time || 24] + end +end diff --git a/app/models/event.rb b/app/models/event.rb index 3a829fd..98f8c29 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,2 +1,17 @@ -class Event < ActiveRecord::Base -end +class Event < ActiveRecord::Base + belongs_to :conference + + def conference_day + return nil unless start_time.present? && end_time.present? + + start_day = conference.start_date.change(hour: 0, minute: 0, second: 0) + w_start_day = start_time.change(hour: 0, minute: 0, second: 0) + return (((w_start_day - start_day) / 86400) + 1).to_i + end + + def duration + return nil unless start_time.present? && end_time.present? + ((end_time - start_time) / 60).to_i + end + +end diff --git a/app/models/event_location.rb b/app/models/event_location.rb new file mode 100644 index 0000000..4f4866a --- /dev/null +++ b/app/models/event_location.rb @@ -0,0 +1,2 @@ +class EventLocation < ActiveRecord::Base +end diff --git a/app/models/workshop.rb b/app/models/workshop.rb index 290c920..e3171cc 100644 --- a/app/models/workshop.rb +++ b/app/models/workshop.rb @@ -87,6 +87,19 @@ class Workshop < ActiveRecord::Base (user.can_translate? && lang.to_sym != locale.to_sym) || can_edit?(user) end + def conference_day + return nil unless start_time.present? && end_time.present? + + start_day = conference.start_date.change(hour: 0, minute: 0, second: 0) + w_start_day = start_time.change(hour: 0, minute: 0, second: 0) + return (((w_start_day - start_day) / 86400) + 1).to_i + end + + def duration + return nil unless start_time.present? && end_time.present? + ((end_time - start_time) / 60).to_i + end + private def make_slug if !self.slug diff --git a/app/views/application/home.html.haml b/app/views/application/home.html.haml index a3fa192..8a85596 100644 --- a/app/views/application/home.html.haml +++ b/app/views/application/home.html.haml @@ -4,16 +4,20 @@ %article %h2=_!@conference.title =@conference.info.html_safe - %h3=_'articles.workshops.headings.Proposed_Workshops' - %p=_'articles.workshops.paragraphs.Proposed_Workshops', "Would you like to facilitate your own workshop? Simply register and visit the workshops page. If you have already registered you can access the page by restarting the registration process." - if @conference.workshops - %ul.workshop-list - - @conference.workshops.sort_by{|w| w.title}.each do |w| - %li - %h4=w.title - .workshop-interest - - if w.interested?(current_user) - =_'articles.workshops.info.you_are_interested_count', "You and #{w.interested_count - 1} others are interested in this workshop", :vars => {:count => (w.interested_count - 1)} - - elsif w.interested_count > 0 - =_'articles.workshops.info.interested_count', "#{w.interested_count} people are interested in this workshop", :vars => {:count => w.interested_count} - .workshop-description=markdown w.info + - if @schedule + %h3=_'articles.workshops.headings.Schedule' + = render 'schedule/programme', :schedule => @schedule, :conference => @conference, :workshops => @workshops, :events => @events, :locations => @locations, :show_interest => true, :day_parts => @day_parts, :show_previews => true + - else + %h3=_'articles.workshops.headings.Proposed_Workshops' + %p=_'articles.workshops.paragraphs.Proposed_Workshops', "Would you like to facilitate your own workshop? Simply register and visit the workshops page. If you have already registered you can access the page by restarting the registration process." + %ul.workshop-list + - @conference.workshops.sort_by{|w| w.title}.each do |w| + %li + %h4=w.title + .workshop-interest + - if w.interested?(current_user) + =_'articles.workshops.info.you_are_interested_count', "You and #{w.interested_count - 1} others are interested in this workshop", :vars => {:count => (w.interested_count - 1)} + - elsif w.interested_count > 0 + =_'articles.workshops.info.interested_count', "#{w.interested_count} people are interested in this workshop", :vars => {:count => w.interested_count} + .workshop-description=markdown w.info diff --git a/app/views/event_locations/edit.html.haml b/app/views/event_locations/edit.html.haml new file mode 100644 index 0000000..6813aec --- /dev/null +++ b/app/views/event_locations/edit.html.haml @@ -0,0 +1,23 @@ += render 'conferences/page_header', :page_key => (@location ? 'Edit_Location' : 'New_Location') +%article + = form_tag save_location_path(@this_conference.slug), class: 'composition' do + = row do + = columns(medium: 12) do + = (hidden_field_tag :location_id, @location.id) if @location + .text-field.input-field.big + = label_tag :title + = text_field_tag :title, @location ? @location.title : nil, :required => true + = row do + = columns(medium: 6) do + .text-area-field.input-field + = label_tag :address + = text_area_tag :address, @location ? @location.address : nil, :required => true + = columns(medium: 6) do + %h3=_'articles.locations.headings.amenities' + - [:sound, :projector, :tools].each do |need| + .single-check-box-field.input-field + = label_tag "needs_#{need}" do + = check_box_tag "needs[#{need}]", 1, @location && @amenities.include?(need) + = _"workshop.options.needs.#{need}" + .actions + = button_tag :save, :value => :save diff --git a/app/views/events/edit.html.haml b/app/views/events/edit.html.haml index 5828e7a..d9afcb7 100644 --- a/app/views/events/edit.html.haml +++ b/app/views/events/edit.html.haml @@ -1,7 +1,22 @@ -%h1 Editing event - -= render 'form' - -= link_to 'Show', @event -\| -= link_to 'Back', events_path += render 'conferences/page_header', :page_key => (@event ? 'Edit_Event' : 'New_Event') +%article + = form_tag save_event_path(@this_conference.slug), class: 'composition' do + = row do + = columns(medium: 9) do + = (hidden_field_tag :event_id, @event.id) if @event + .text-field.input-field.big + = label_tag :title + = text_field_tag :title, @event ? @event.title : nil, :required => true + = columns(medium: 3) do + .select-field.input-field + = label_tag :event_type do + = select_tag :event_type, options_for_select([:event, :meal], @event ? @event.event_type : nil), :include_blank => true + =_'forms.labels.generic.event_type' + = row do + = columns(medium: 12) do + .text-area-field.input-field + = label_tag :info + = text_area_tag :info, @event ? @event.info : nil, :required => true + = columns(medium: 12) do + .actions.right + = button_tag :save, :value => :save diff --git a/app/views/schedule/_programme.html.haml b/app/views/schedule/_programme.html.haml new file mode 100644 index 0000000..75101b0 --- /dev/null +++ b/app/views/schedule/_programme.html.haml @@ -0,0 +1,36 @@ +.programme + - schedule.each do |day, day_schedule| + .programme-day + %h2=I18n.l(conference.start_date + (day - 1).days, :format => "%A") + - (0...day_parts.length).each do |day_part| + .programme-day-part + - times = schedule_start_and_end_times(day_part, day_parts, day_schedule) + - if times.present? + %h3=_"articles.headings.schedule.day_parts.#{day_parts.keys[day_part].to_s}" if day_parts.length > 1 + %table.schedule + %tr + %th + - (times.first...times.last).step(0.5).each do |t| + - t = t.to_i if t == t.to_i + %th=I18n.l(Date.today + t.hours, :format => :short) + - day_schedule[:locations].each do |location, location_schedule| + %tr + %th=locations[location.to_s].title + - skip = 0 + - (times.first...times.last).step(0.5).each do |t| + - t = t.to_i if t == t.to_i + - if location_schedule[t].present? + - workshop = location_schedule[t] + - w = get_workshop(workshop, workshops, events) + %td{:class => workshop_classes(w, show_interest) + [show_previews && workshop[:type] == :workshop ? 'previewable' : nil], :colspan => (workshop[:span] * 2), :id => "workshop-#{w.id}"} + .title= w.title + - if show_previews && workshop[:type] == :workshop + .info + %a.close{href: "#!"} + = render 'workshops/show', :workshop => w, :preview => true + %a{class: 'preview', href: "#workshop-#{w.id}"} + - skip = workshop[:span] - 0.5 + - elsif skip > 0 + - skip -= 0.5 + - else + %td.empty diff --git a/app/views/schedule/edit.html.haml b/app/views/schedule/edit.html.haml new file mode 100644 index 0000000..bcc06a0 --- /dev/null +++ b/app/views/schedule/edit.html.haml @@ -0,0 +1,77 @@ += render 'conferences/page_header', :page_key => 'Edit_Schedule' +%article + = form_tag save_schedule_path(@this_conference.slug), class: 'composition' do + = row do + = columns(medium: 12) do + = render 'schedule/programme', :schedule => @schedule, :conference => @this_conference, :workshops => @workshops, :events => @events, :locations => @location_hash, :show_interest => false, :day_parts => @day_parts, :show_previews => false + = row do + = columns(medium: 12) do + - if @error_count && @error_count > 0 + %h3.errors + =_'errors.schedule.errors',"Errors:" + = @error_count + - if @conflict_score && @conflict_score > 0 + %h3.conflict-score + =_'errors.schedule.conflict_score',"Interest Conflicts:" + = @conflict_score + = row do + = columns(medium: 12) do + = (hidden_field_tag :location_id, @location.id) if @location + .actions + - if @this_conference.workshop_schedule_published + = button_tag :Unpublish, :value => :unpublish, :class => 'delete' + - elsif @error_count < 1 + = button_tag :Publish, :value => :publish + = button_tag :Preview, :value => :preview, :class => 'secondary' + - unless @this_conference.workshop_schedule_published && @error_count > 0 + = button_tag :save, :value => :save + - unless @saved + .unsaved=_'errors.schedule.unsaved','Your changes will not be saved until you press Save or Publish' + = row do + = columns(medium: 6) do + %h2=_"articles.headings.schedule.day_parts.Workshops" + %ul.all-workshops + - @workshops.each do |i| + - error = @errors["w#{i.id}"] + - warnings = @warnings["w#{i.id}"] + %li{class: error.present? ? :error : nil} + %h3=i.title + .workshop-interest=_'articles.workshops.info.interested_count', "#{i.interested_count} people are interested in this workshop", :vars => {:count => i.interested_count} + .time + = select_tag "workshop_day[#{i.id}]", options_for_select(@days, i.conference_day), :include_blank => true + = select_tag "workshop_hour[#{i.id}]", options_for_select(@hours, i.start_time ? i.start_time.strftime('%R') : nil), :include_blank => true + = select_tag "workshop_duration[#{i.id}]", options_for_select(@workshop_durations, i.duration || 60) + .location + = select_tag "workshop_location[#{i.id}]", options_from_collection_for_select(@locations, :id, :title, i.event_location_id), :include_blank => true + - if warnings + %ul.warnings + - warnings.each do |warning| + %li=warning + - if error + .error-description=error + = columns(medium: 6) do + %h2=_"articles.headings.schedule.day_parts.Events" + %ul.all-events + - @events.each do |i| + - error = @errors["e#{i.id}"] + %li{:class => [i.event_type, error.present? ? :error : nil]} + %h3=i.title + .time + = select_tag "event_day[#{i.id}]", options_for_select(@days, i.conference_day) + = select_tag "event_hour[#{i.id}]", options_for_select(@hours, i.start_time ? i.start_time.strftime('%R') : '12:00') + = select_tag "event_duration[#{i.id}]", options_for_select(@event_durations, i.duration || 60) + .location + = select_tag "event_location[#{i.id}]", options_from_collection_for_select(@locations, :id, :title, i.event_location_id), :include_blank => true + - if error + .error-description=error + %h2=_"articles.headings.schedule.day_parts.Day_Parts" + %ul.day_parts + - [:morning, :afternoon, :evening].each do |day_part| + %li + %h4 + =_"articles.headings.schedule.day_parts.#{day_part.to_s}" + - h = (Date.today + @day_parts[day_part.to_s].to_f.hours).strftime('%R') + - if day_part == :morning + .select=h + - else + = select_tag "day_parts[#{day_part.to_s}]", options_for_select(@hours, h) diff --git a/app/views/schedule/show.html.haml b/app/views/schedule/show.html.haml new file mode 100644 index 0000000..a3c0839 --- /dev/null +++ b/app/views/schedule/show.html.haml @@ -0,0 +1,28 @@ += render 'conferences/page_header', :page_key => 'Schedule' +%article + - if @this_conference.host?(current_user) + = row do + = columns(medium: 12) do + .actions.left + = link_to (_'actions.schedule.edit','Edit Schedule'), edit_schedule_path(@this_conference.slug), class: [:button] + = row do + = columns(medium: 6) do + %h2=_'articles.schedule.headings.Events' + - if @events + %ul + - @events.each do |event| + %li + %h3=_!event.title + = link_to (_'actions.events.edit','Edit'), edit_event_path(@this_conference.slug, event.id), class: [:button, :modify] + .actions.left + = link_to (_'actions.events.create','Add Event'), add_event_path(@this_conference.slug), class: [:button, :modify] + = columns(medium: 6) do + %h2=_'articles.schedule.headings.Locations' + - if @locations + %ul + - @locations.each do |location| + %li + %h3=_!location.title + = link_to (_'actions.locations.edit','Edit'), edit_location_path(@this_conference.slug, location.id), class: [:button, :modify] + .actions.left + = link_to (_'actions.schedule.edit','Add Location'), add_location_path(@this_conference.slug), class: [:button, :modify] diff --git a/app/views/workshops/_show.html.haml b/app/views/workshops/_show.html.haml new file mode 100644 index 0000000..54bb221 --- /dev/null +++ b/app/views/workshops/_show.html.haml @@ -0,0 +1,58 @@ += row do + = columns(medium: 12) do + %h2=_!workshop.title + .workshop-interest + - if workshop.interested?(current_user) + =_'articles.workshops.info.you_are_interested_count', "You and #{workshop.interested_count - 1} others are interested in this workshop", :vars => {:count => (workshop.interested_count - 1)} + - else + =_'articles.workshops.info.interested_count', "#{workshop.interested_count} people are interested in this workshop", :vars => {:count => workshop.interested_count} + - if !preview && workshop.can_show_interest?(current_user) + = form_tag toggle_workshop_interest_path(workshop.conference.slug, workshop.id) do + = button_tag (workshop.interested?(current_user) ? :remove_interest : :show_interest), :value => :toggle_interest, :class => (workshop.interested?(current_user) ? 'delete' : 'add') + =markdown _!(workshop.info) || '' + - if !preview && logged_in? && current_user.can_translate? + .actions + - I18n.backend.enabled_locales.each do |locale| + = (link_to (_'actions.workshops.Translate', "Translate into #{language_name(locale)}", :vars => {:language => language_name(locale)}), edit_workshop_url(workshop.conference.slug, workshop.id, url_params(locale)), :class => 'button translate') if workshop.can_translate?(current_user, locale) + = columns(medium: 6) do + %h3=_'articles.workshops.headings.facilitators' + .facilitators + - workshop.workshop_facilitators.each do |f| + - u = User.find(f.user_id) + - if logged_in? && (workshop.public_facilitator?(u) || f.user_id == current_user.id || workshop.active_facilitator?(current_user)) + .facilitator + .name=_!(u.firstname || u.username || u.email) + .role + =_"roles.workshops.facilitator.#{workshop.role(u).to_s}" + - if !preview && f.role.to_sym == :requested && workshop.active_facilitator?(current_user) + =(link_to (_'actions.workshops.Approve'), approve_facilitate_workshop_request_path(workshop.conference.slug, workshop.id, f.user_id, 'approve'), :class => 'button modify') + =(link_to (_'actions.workshops.Deny'), approve_facilitate_workshop_request_path(workshop.conference.slug, workshop.id, f.user_id, 'deny'), :class => 'button delete') + - elsif !preview && (f.user_id == current_user.id && f.role.to_sym != :creator) || (!workshop.conference.registered?(u) && workshop.active_facilitator?(current_user)) + =(link_to (_'actions.workshops.Remove'), approve_facilitate_workshop_request_path(workshop.conference.slug, workshop.id, f.user_id, 'remove'), :class => 'button delete') + - if !preview + .actions + =(link_to (_'actions.workshops.Facilitate'), facilitate_workshop_path(workshop.conference.slug, workshop.id), :class => 'button modify') if !workshop.facilitator?(current_user) + - if workshop.active_facilitator?(current_user) + = form_tag workshop_add_facilitator_path(workshop.conference.slug, workshop.id), :class => 'add-facilitator' do + %h4='Add a facilitator' + .email-field.input-field + = email_field_tag :email, nil, required: true + = label_tag :email + = button_tag :add + - if workshop.languages + = columns(medium: 6) do + %h3=_'articles.workshops.headings.languages','Workshop Language' + %p= _!((JSON.parse(workshop.languages || '[]').map { |x| _"languages.#{x}" }).join(', ').to_s.html_safe) + - if workshop.theme + = columns(medium: 6) do + %h3=_'articles.workshops.headings.theme','Theme' + %p= [:race_gender, :mechanics, :funding, :organization, :community].include?((workshop.theme || '').to_sym) ? (_"workshop.options.theme.#{workshop.theme}") : workshop.theme + - if workshop.active_facilitator?(current_user) || workshop.conference.host?(current_user) + - if workshop.needs + = columns(medium: 6) do + %h3=_'articles.workshops.headings.needs','What do you need?' + %p= _!((JSON.parse(workshop.needs || '[]').map { |x| _"workshop.options.needs.#{x}" }).join(', ').to_s.html_safe) + - if workshop.notes + = columns(medium: 12) do + %h3=_'articles.workshops.headings.notes','Notes' + =markdown _!(workshop.notes) diff --git a/app/views/workshops/show.html.haml b/app/views/workshops/show.html.haml index caec851..3a7cd4d 100644 --- a/app/views/workshops/show.html.haml +++ b/app/views/workshops/show.html.haml @@ -1,62 +1,7 @@ = render 'conferences/page_header', :page_key => 'View_Workshop' %article + = render 'workshops/show', :workshop => @workshop, :preview => false = row do - = columns(medium: 12) do - %h2=_!@workshop.title - .workshop-interest - - if @workshop.interested?(current_user) - =_'articles.workshops.info.you_are_interested_count', "You and #{@workshop.interested_count - 1} others are interested in this workshop", :vars => {:count => (@workshop.interested_count - 1)} - - else - =_'articles.workshops.info.interested_count', "#{@workshop.interested_count} people are interested in this workshop", :vars => {:count => @workshop.interested_count} - - if @workshop.can_show_interest?(current_user) - = form_tag toggle_workshop_interest_path(@this_conference.slug, @workshop.id) do - = button_tag (@workshop.interested?(current_user) ? :remove_interest : :show_interest), :value => :toggle_interest, :class => (@workshop.interested?(current_user) ? 'delete' : 'add') - =markdown _!(@workshop.info) || '' - - if current_user.can_translate? - .actions - - I18n.backend.enabled_locales.each do |locale| - = (link_to (_'actions.workshops.Translate', "Translate into #{language_name(locale)}", :vars => {:language => language_name(locale)}), edit_workshop_url(@this_conference.slug, @workshop.id, url_params(locale)), :class => 'button translate') if @workshop.can_translate?(current_user, locale) - = columns(medium: 6) do - %h3=_'articles.workshops.headings.facilitators' - .facilitators - - @workshop.workshop_facilitators.each do |f| - - u = User.find(f.user_id) - - if @workshop.public_facilitator?(u) || f.user_id == current_user.id || @workshop.active_facilitator?(current_user) - .facilitator - .name=_!(u.firstname || u.username || u.email) - .role - =_"roles.workshops.facilitator.#{@workshop.role(u).to_s}" - - if f.role.to_sym == :requested && @workshop.active_facilitator?(current_user) - =(link_to (_'actions.workshops.Approve'), approve_facilitate_workshop_request_path(@this_conference.slug, @workshop.id, f.user_id, 'approve'), :class => 'button modify') - =(link_to (_'actions.workshops.Deny'), approve_facilitate_workshop_request_path(@this_conference.slug, @workshop.id, f.user_id, 'deny'), :class => 'button delete') - - elsif (f.user_id == current_user.id && f.role.to_sym != :creator) || (!@this_conference.registered?(u) && @workshop.active_facilitator?(current_user)) - =(link_to (_'actions.workshops.Remove'), approve_facilitate_workshop_request_path(@this_conference.slug, @workshop.id, f.user_id, 'remove'), :class => 'button delete') - .actions - =(link_to (_'actions.workshops.Facilitate'), facilitate_workshop_path(@this_conference.slug, @workshop.id), :class => 'button modify') if !@workshop.facilitator?(current_user) - - if @workshop.active_facilitator?(current_user) - = form_tag workshop_add_facilitator_path(@this_conference.slug, @workshop.id), :class => 'add-facilitator' do - %h4='Add a facilitator' - .email-field.input-field - = email_field_tag :email, nil, required: true - = label_tag :email - = button_tag :add - - if @workshop.languages - = columns(medium: 6) do - %h3=_'articles.workshops.headings.languages','Workshop Language' - %p= _!((JSON.parse(@workshop.languages || '[]').map { |x| _"languages.#{x}" }).join(', ').to_s.html_safe) - - if @workshop.theme - = columns(medium: 6) do - %h3=_'articles.workshops.headings.theme','Theme' - %p= [:race_gender, :mechanics, :funding, :organization, :community].include?((@workshop.theme || '').to_sym) ? (_"workshop.options.theme.#{@workshop.theme}") : @workshop.theme - - if @workshop.active_facilitator?(current_user) || @this_conference.host?(current_user) - - if @workshop.needs - = columns(medium: 6) do - %h3=_'articles.workshops.headings.needs','What do you need?' - %p= _!((JSON.parse(@workshop.needs || '[]').map { |x| _"workshop.options.needs.#{x}" }).join(', ').to_s.html_safe) - - if @workshop.notes - = columns(medium: 12) do - %h3=_'articles.workshops.headings.notes','Notes' - =markdown _!(@workshop.notes) = columns(medium: 12) do .actions.right = (link_to (_'actions.workshops.Edit'), edit_workshop_path(@this_conference.slug, @workshop.id), :class => 'button modify') if @workshop.can_edit?(current_user) diff --git a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--.html b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--.html index 97a8d9b..052f244 100644 --- a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--.html +++ b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--.html @@ -46,7 +46,7 @@

Guadalajara, Jalisco, Mexico

-August 22 – 26, 2015 +August 27 – 31, 2015
diff --git a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-1.html b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-1.html index 75d25d4..e0e18be 100644 --- a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-1.html +++ b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-1.html @@ -51,7 +51,7 @@
-

Mauris Enim Leo, Rhoncus Sed, Vestibulum Sit Amet, Cursus Id, Turpis

+

Sed Accumsan Felis

You are interested in this workshop
@@ -59,7 +59,7 @@
-

Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam. Suspendisse potenti.

+

Proin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.

Facilitators

@@ -67,7 +67,8 @@ Make a facilitation request
-
+
+
diff --git a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-2.html b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-2.html index 0e8807a..5c2caea 100644 --- a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-2.html +++ b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1-2.html @@ -51,7 +51,7 @@
-

Mauris Enim Leo, Rhoncus Sed, Vestibulum Sit Amet, Cursus Id, Turpis

+

Sed Accumsan Felis

No one is interested in this workshop yet
@@ -59,7 +59,7 @@
-

Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam. Suspendisse potenti.

+

Proin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.

Facilitators

@@ -67,7 +67,8 @@ Make a facilitation request
-
+
+
diff --git a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1.html b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1.html index 0e8807a..5c2caea 100644 --- a/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1.html +++ b/config/locales/data/html_records/Be-the-first-to-like-a-workshop--conferences.MyBikeBike.workshops.1.html @@ -51,7 +51,7 @@
-

Mauris Enim Leo, Rhoncus Sed, Vestibulum Sit Amet, Cursus Id, Turpis

+

Sed Accumsan Felis

No one is interested in this workshop yet
@@ -59,7 +59,7 @@
-

Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam. Suspendisse potenti.

+

Proin interdum mauris non ligula pellentesque ultrices. Phasellus id sapien in sapien iaculis congue. Vivamus metus arcu, adipiscing molestie, hendrerit at, vulputate vitae, nisl.

Facilitators

@@ -67,7 +67,8 @@ Make a facilitation request
-
+
+
diff --git a/config/locales/data/html_records/Broadcast-message--.html b/config/locales/data/html_records/Broadcast-message--.html index c4e65bc..e4ad3d8 100644 --- a/config/locales/data/html_records/Broadcast-message--.html +++ b/config/locales/data/html_records/Broadcast-message--.html @@ -46,7 +46,7 @@

San Marcos, Texas

-August 22 – 26, 2015 +August 27 – 31, 2015
diff --git a/config/locales/data/html_records/Broadcast-message--conferences.MyBikeBike.broadcast-1.html b/config/locales/data/html_records/Broadcast-message--conferences.MyBikeBike.broadcast-1.html index e31ec46..42e7393 100644 --- a/config/locales/data/html_records/Broadcast-message--conferences.MyBikeBike.broadcast-1.html +++ b/config/locales/data/html_records/Broadcast-message--conferences.MyBikeBike.broadcast-1.html @@ -47,6 +47,7 @@