Class: CalendarizeHelper::DailyCalendarBuilder

Inherits:
AbstractCalendarBuilder show all
Defined in:
app/helpers/calendarize_helper.rb

Instance Attribute Summary

Attributes inherited from AbstractCalendarBuilder

#event, #is_all_day

Instance Method Summary collapse

Constructor Details

#initialize(view_context, *args) ⇒ DailyCalendarBuilder

Returns a new instance of DailyCalendarBuilder.



257
258
259
260
261
262
263
264
265
266
267
# File 'app/helpers/calendarize_helper.rb', line 257

def initialize(view_context, *args)

  opts = {
    id: "daily_calendar_#{@@uuid}",
    scope: 'daily'
  }.merge!(args.extract_options!)

  args << opts

  super(view_context, *args)
end

Instance Method Details

#computeObject



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'app/helpers/calendarize_helper.rb', line 270

def compute

  super

  # Partition the events between all-day and :not all-day events
  # Then, for the :not all-day events, put them in rows
  rows_events = {}
  @all_day_events, not_all_day_events = @events.partition { |e| e.end_time.to_date > @day }

  not_all_day_events.each do |e|
    row_unit = row_unit(e.start_time)

    if !rows_events.has_key?(row_unit)
      rows_events[row_unit] = [e]
    else
      rows_events[row_unit] << e
    end
  end

  # We remove the events that:
  # - start or end before the :starting_row
  # - start or end after the :ending_row
  rows_events.each_value { |r| r.reject! { |e| row_unit(e.start_time) >= @_ending_row || row_unit(e.start_time) < @_starting_row } }
  rows_events.each_value { |r| r.reject! { |e| row_unit(e.end_time)   >= @_ending_row || row_unit(e.end_time)   < @_starting_row } }

  # Sort each row (that now contains events) by the duration of the event
  rows_events.each_value { |r| r.sort! { |e1, e2| e2.end_time - e2.start_time <=> e1.end_time - e1.start_time } }

  # Put the events in columns, which give a tuple '[[row_start, row_end, column], event]' for the event
  # that will be used to output the calendar. The algorithm works like this:
  # - As we cycle in the rows (which contains events that start at the same :unit time), we create columns and
  #   we keep track of what we put in the columns
  # - When to decide in which column to put an event, we start from the column 0 and check the :end_time of the
  #   last event inserted in that column. If this :end_time is less than the :start_time of the event we want
  #   to insert, we have a candidate!
  columns = {}
  @placed_events = []

  rows_events.each do |i,v|
    v.each do |e|
      j = 0
      placed = false

      while (!placed) do
        if !columns.has_key?(j)
          columns[j] = [e]
          @placed_events << [[i, i + ((e.end_time - e.start_time) / (60 * @options[:unit])).ceil, j], e]
          placed = true
        elsif (row(e.start_time) >= row(columns[j].last.end_time))
          columns[j] << e
          @placed_events << [[i, i + ((e.end_time - e.start_time) / (60 * @options[:unit])).ceil, j], e]
          placed = true
        else
          j += 1
        end
      end
    end
  end

  # We make a list of all the rows to render
  # If we set the option :verbose to false, we only show the rows that have events
  occupied_rows = []
  @placed_events.each { |tuple| occupied_rows << (tuple[0][0]...tuple[0][1]).to_a }
  occupied_rows.flatten!
  occupied_rows.uniq!
  @rows_to_render_indexes = @options[:verbose] ? @rows.map.with_index { |x, i| i } : occupied_rows.map { |r| @rows.index(r) }

  self
end

#render(&block) ⇒ Object



341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'app/helpers/calendarize_helper.rb', line 341

def render(&block)
  (:div, class: 'daily_calendar', id: @options[:id], style: 'position: relative;') do

    tables = ''.html_safe

    # controls
    tables << (:table, id: 'controls', class: 'styled', style: 'width: 100%;') do
      (:thead) do
        (:tr) do
          content = ''.html_safe
          content << (:th, style: 'width: 33%;') { link_to(@options[:verbose] ? I18n.t('calendarize.daily_calendar.options.verbose', default: 'Compact') : I18n.t('calendarize.daily_calendar.options.not_verbose', default: 'Full'), @options[:url] + '?' + to_query_params({ date: @day.to_date, verbose: !@options[:verbose] })) }
          content << (:th, style: 'width: 33%;') { I18n.l(@day.to_date, format: @options[:date_format]) }
          content << (:th, style: 'width: 33%;') do
            options = ''.html_safe
            options << link_to(I18n.t('calendarize.daily_calendar.options.previous_day', default: 'Previous day'), @options[:url] + '?' +  to_query_params({ date: @day.yesterday.to_date }))
            options << ' | '
            options << link_to(I18n.t('calendarize.daily_calendar.options.today', default: 'Today'), @options[:url] + '?' + to_query_params)
            options << ' | '
            options << link_to(I18n.t('calendarize.daily_calendar.options.next_day', default: 'Next day'), @options[:url] + '?' + to_query_params({ date: @day.tomorrow.to_date }))
            options
          end
          content
        end
      end
    end

    # all day events
    tables << (:table, id: 'all_day', class: 'styled', style: 'width: 100%;') do
      content = ''.html_safe
      content << (:thead) do
        (:tr) do
          (:th) { I18n.t('calendarize.daily_calendar.all_day_events', default: 'All day events') }
        end
      end

      content << (:tbody) do

        trs = ''.html_safe

        @all_day_events.each_index do |i|
          trs << (:tr) do
            @event = @all_day_events[i]
            @is_all_day = true
            (:td, class: 'row_content', id: "row_content_#{i}") { @view_context.capture(self, &block) }
          end
        end

        trs
      end

      content
    end unless @all_day_events.empty?

    # normal events
    tables << (:table, id: 'not_all_day', class: 'styled', style: 'width: 100%;') do
      content = ''.html_safe
      content << (:thead) do
        (:tr) do
          header = ''.html_safe
          header << (:th, style: 'width: 40px;') { I18n.t('calendarize.daily_calendar.hours', default: 'Hours') }
          header << (:th) { }
          header
        end
      end

      content << (:tbody) do

        trs = ''.html_safe

        #raise @rows.inspect
        @rows_to_render_indexes.each do |i|
          trs << (:tr, class: 'row_unit', style: 'height: 50px;') do
            tds = ''.html_safe
            tds << (:td, class: 'row_header', id: "row_header_#{@rows[i]}", style: 'width: 40px') { @rows_hours[i].strftime('%H:%M') }
            tds << (:td, class: 'row_content', id: "row_content_#{@rows[i]}") { }
            tds
          end
        end

        trs
      end

      content
    end

    # place the events at the end of the calendar
    # they will be placed at the right place on the calendar with some javascript magic
    @placed_events.each do |e|
      #raise e.inspect
      @event = e[1]
      @is_all_day = false
      tables << (:div, class: 'calendar_event', data: { row_start: e[0][0], row_end: e[0][1], column: e[0][2] }, style: 'z-index: 1;') do
        (:div, class: 'content') { @view_context.capture(self, &block) }
      end
    end

    tables
  end
end