summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/postrunner/ActivitiesDB.rb21
-rw-r--r--lib/postrunner/Activity.rb3
-rw-r--r--lib/postrunner/ActivityLink.rb59
-rw-r--r--lib/postrunner/ActivityListView.rb126
-rw-r--r--lib/postrunner/ActivitySummary.rb12
-rw-r--r--lib/postrunner/ActivityView.rb124
-rw-r--r--lib/postrunner/ChartView.rb30
-rw-r--r--lib/postrunner/DeviceList.rb10
-rw-r--r--lib/postrunner/FlexiTable.rb29
-rw-r--r--lib/postrunner/HTMLBuilder.rb80
-rw-r--r--lib/postrunner/NavButtonRow.rb103
-rw-r--r--lib/postrunner/PagingButtons.rb77
-rw-r--r--lib/postrunner/PersonalRecords.rb47
-rw-r--r--lib/postrunner/RecordListPageView.rb69
-rw-r--r--lib/postrunner/TrackView.rb30
-rw-r--r--lib/postrunner/UserProfileView.rb8
-rw-r--r--lib/postrunner/View.rb97
-rw-r--r--lib/postrunner/ViewBottom.rb54
-rw-r--r--lib/postrunner/ViewButtons.rb68
-rw-r--r--lib/postrunner/ViewFrame.rb93
-rw-r--r--lib/postrunner/ViewTop.rb80
-rw-r--r--lib/postrunner/ViewWidgets.rb153
22 files changed, 973 insertions, 400 deletions
diff --git a/lib/postrunner/ActivitiesDB.rb b/lib/postrunner/ActivitiesDB.rb
index f63e30a..b6516e7 100644
--- a/lib/postrunner/ActivitiesDB.rb
+++ b/lib/postrunner/ActivitiesDB.rb
@@ -18,12 +18,13 @@ require 'postrunner/BackedUpFile'
require 'postrunner/Activity'
require 'postrunner/PersonalRecords'
require 'postrunner/ActivityListView'
+require 'postrunner/ViewButtons'
module PostRunner
class ActivitiesDB
- attr_reader :db_dir, :cfg, :fit_dir, :activities, :records
+ attr_reader :db_dir, :cfg, :fit_dir, :activities, :records, :views
def initialize(db_dir, cfg)
@db_dir = db_dir
@@ -59,6 +60,14 @@ module PostRunner
sync_needed |= !a.fit_activity.nil?
end
+ # Define which View objects the HTML output will contain off. This
+ # doesn't really belong in ActivitiesDB but for now it's the best place
+ # to put it.
+ @views = ViewButtons.new([
+ NavButtonDef.new('activities.png', 'index.html'),
+ NavButtonDef.new('record.png', "records-0.html")
+ ])
+
@records = PersonalRecords.new(self)
sync if sync_needed
end
@@ -164,12 +173,12 @@ module PostRunner
def check
@records.delete_all_records
- @activities.sort! do |a1, a2|
+ @activities.sort do |a1, a2|
a1.timestamp <=> a2.timestamp
end.each { |a| a.check }
@records.sync
# Ensure that HTML index is up-to-date.
- ActivityListView.new(self).update_html_index
+ ActivityListView.new(self).update_index_pages
end
def ref_by_fit_file(fit_file)
@@ -265,7 +274,7 @@ module PostRunner
# Show the activity list in a web browser.
def show_list_in_browser
- ActivityListView.new(self).update_html_index
+ ActivityListView.new(self).update_index_pages
show_in_browser(File.join(@cfg[:html_dir], 'index.html'))
end
@@ -300,7 +309,7 @@ module PostRunner
@activities.each { |a| a.generate_html_view }
Log.info "All HTML report files have been re-generated."
# (Re-)generate index files.
- ActivityListView.new(self).update_html_index
+ ActivityListView.new(self).update_index_pages
Log.info "HTML index files have been updated."
end
@@ -332,7 +341,7 @@ module PostRunner
end
@records.sync
- ActivityListView.new(self).update_html_index
+ ActivityListView.new(self).update_index_pages
end
def create_directory(dir, name)
diff --git a/lib/postrunner/Activity.rb b/lib/postrunner/Activity.rb
index e0e1e06..b4a38f4 100644
--- a/lib/postrunner/Activity.rb
+++ b/lib/postrunner/Activity.rb
@@ -312,8 +312,7 @@ module PostRunner
def generate_html_view
@fit_activity = load_fit_file unless @fit_activity
- ActivityView.new(self, @db.cfg[:unit_system], @db.predecessor(self),
- @db.successor(self))
+ ActivityView.new(self, @db.cfg[:unit_system])
end
def activity_type
diff --git a/lib/postrunner/ActivityLink.rb b/lib/postrunner/ActivityLink.rb
new file mode 100644
index 0000000..9c368b0
--- /dev/null
+++ b/lib/postrunner/ActivityLink.rb
@@ -0,0 +1,59 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = ActivityLink.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/HTMLBuilder'
+
+module PostRunner
+
+ # Generates the name of an Activity with a link to the ActivityReport.
+ # Optionally, an icon can be shown for Activities that contain a current
+ # personal record.
+ class ActivityLink
+
+ def initialize(activity, show_record_icon = false)
+ @activity = activity
+ @show_record_icon = show_record_icon
+ end
+
+ # Add the ActivityLink as HTML Elements to the document.
+ # @param doc [HTMLBuilder] XML Document
+ def to_html(doc)
+ doc.unique(:activitylink_style) { doc.style(style) }
+
+ doc.a(@activity.name, { :class => 'activity_link',
+ :href => @activity.fit_file[0..-5] + '.html' })
+ if @show_record_icon && @activity.has_records?
+ doc.img(nil, { :src => 'icons/record-small.png',
+ :style => 'vertical-align:middle' })
+ end
+ end
+
+ # Convert the ActivityLink into a plain text form. Return the first 20
+ # characters of the Activity name.
+ def to_s
+ @activity.name[0..19]
+ end
+
+ private
+
+ def style
+ <<EOT
+.activity_link {
+ padding: 0px 3px 0px 3px;
+}
+EOT
+ end
+
+ end
+
+end
+
diff --git a/lib/postrunner/ActivityListView.rb b/lib/postrunner/ActivityListView.rb
index 643754b..8027cb0 100644
--- a/lib/postrunner/ActivityListView.rb
+++ b/lib/postrunner/ActivityListView.rb
@@ -14,35 +14,15 @@ require 'fit4ruby'
require 'postrunner/FlexiTable'
require 'postrunner/HTMLBuilder'
-require 'postrunner/ViewWidgets'
+require 'postrunner/ActivityLink'
module PostRunner
+ # Generates a paged list of all Activity objects in the database. HTML and
+ # plain text output are supported.
class ActivityListView
- class ActivityLink
-
- def initialize(activity)
- @activity = activity
- end
-
- def to_html(doc)
- doc.a(@activity.name, { :class => 'activity_link',
- :href => @activity.fit_file[0..-5] + '.html' })
- if @activity.has_records?
- doc.img(nil, { :src => 'icons/record-small.png',
- :style => 'vertical-align:middle' })
- end
- end
-
- def to_s
- @activity.name[0..19]
- end
-
- end
-
include Fit4Ruby::Converters
- include ViewWidgets
def initialize(db)
@db = db
@@ -52,85 +32,42 @@ module PostRunner
@last_page = (@db.activities.length - 1) / @page_size
end
- def update_html_index
+ def update_index_pages
0.upto(@last_page) do |page_no|
@page_no = page_no
- generate_html_index_page
+ generate_html_index_page(page_no)
end
end
- def to_html(doc)
- generate_table.to_html(doc)
- end
-
def to_s
generate_table.to_s
end
private
- def generate_html_index_page
- doc = HTMLBuilder.new
+ def generate_html_index_page(page_index)
+ views = @db.views
+ views.current_page = 'index.html'
- doc.html {
- head(doc)
- body(doc)
- }
-
- write_file(doc)
- end
+ pages = PagingButtons.new((0..@last_page).map do |i|
+ "index#{i == 0 ? '' : "-#{i}"}.html"
+ end)
+ pages.current_page =
+ "index#{page_index == 0 ? '' : "-#{page_index}"}.html"
+ @view = View.new("PostRunner Activities", views, pages)
- def head(doc)
- doc.head {
- doc.meta({ 'http-equiv' => 'Content-Type',
- 'content' => 'text/html; charset=utf-8' })
- doc.title("PostRunner Activities")
- style(doc)
- }
- end
+ @view.doc.head { @view.doc.style(style) }
+ body(@view.doc)
- def style(doc)
- view_widgets_style(doc)
- doc.style(<<EOT
-body {
- font-family: verdana,arial,sans-serif;
- margin: 0px;
-}
-.main {
- text-align: center;
-}
-.widget_frame {
- width: 900px;
-}
-.activity_link {
- padding: 0px 3px 0px 3px;
-}
-.ft_cell {
- height: 30px
-}
-EOT
- )
+ output_file = File.join(@db.cfg[:html_dir], pages.current_page)
+ @view.write(output_file)
end
def body(doc)
- doc.body {
- first_page = @page_no == 0 ? nil: 'index.html'
- prev_page = @page_no == 0 ? nil :
- @page_no == 1 ? 'index.html' :
- "index#{@page_no - 1}.html"
- prev_page = @page_no == 0 ? nil :
- @page_no == 1 ? 'index.html' :
- "index#{@page_no - 1}.html"
- next_page = @page_no < @last_page ? "index#{@page_no + 1}.html" : nil
- last_page = @page_no == @last_page ? nil : "index#{@last_page}.html"
- titlebar(doc, first_page, prev_page, nil, next_page, last_page)
-
+ @view.body {
doc.div({ :class => 'main' }) {
- frame(doc, 'Activities') {
- generate_table.to_html(doc)
- }
+ ViewFrame.new('Activities', 900, generate_table).to_html(doc)
}
- footer(doc)
}
end
@@ -154,7 +91,7 @@ EOT
activities.each do |a|
t.row([
i += 1,
- ActivityLink.new(a),
+ ActivityLink.new(a, true),
a.activity_type,
a.timestamp.strftime("%a, %Y %b %d %H:%M"),
local_value(a.total_distance, 'm', '%.2f',
@@ -168,14 +105,19 @@ EOT
t
end
- def write_file(doc)
- output_file = File.join(@db.cfg[:html_dir],
- "index#{@page_no == 0 ? '' : @page_no}.html")
- begin
- File.write(output_file, doc.to_html)
- rescue IOError
- Log.fatal "Cannot write activity index file '#{output_file}: #{$!}"
- end
+ def style
+ <<EOT
+body {
+ font-family: verdana,arial,sans-serif;
+ margin: 0px;
+}
+.main {
+ text-align: center;
+}
+.ft_cell {
+ height: 30px
+}
+EOT
end
def local_value(value, from_unit, format, units)
diff --git a/lib/postrunner/ActivitySummary.rb b/lib/postrunner/ActivitySummary.rb
index ab283cb..ffb0901 100644
--- a/lib/postrunner/ActivitySummary.rb
+++ b/lib/postrunner/ActivitySummary.rb
@@ -13,14 +13,13 @@
require 'fit4ruby'
require 'postrunner/FlexiTable'
-require 'postrunner/ViewWidgets'
+require 'postrunner/ViewFrame'
module PostRunner
class ActivitySummary
include Fit4Ruby::Converters
- include ViewWidgets
def initialize(fit_activity, unit_system, custom_fields)
@fit_activity = fit_activity
@@ -35,12 +34,9 @@ module PostRunner
end
def to_html(doc)
- frame(doc, "Activity: #{@name}") {
- summary.to_html(doc)
- }
- frame(doc, 'Laps') {
- laps.to_html(doc)
- }
+ width = 600
+ ViewFrame.new("Activity: #{@name}", width, summary).to_html(doc)
+ ViewFrame.new('Laps', width, laps).to_html(doc)
end
private
diff --git a/lib/postrunner/ActivityView.rb b/lib/postrunner/ActivityView.rb
index fa05e4c..bba1ec7 100644
--- a/lib/postrunner/ActivityView.rb
+++ b/lib/postrunner/ActivityView.rb
@@ -3,7 +3,7 @@
#
# = ActivityView.rb -- PostRunner - Manage the data from your Garmin sport devices.
#
-# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
+# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@@ -12,70 +12,75 @@
require 'fit4ruby'
-require 'postrunner/HTMLBuilder'
+require 'postrunner/View'
require 'postrunner/ActivitySummary'
require 'postrunner/DeviceList'
require 'postrunner/UserProfileView'
-require 'postrunner/ViewWidgets'
require 'postrunner/TrackView'
require 'postrunner/ChartView'
module PostRunner
- class ActivityView
+ class ActivityView < View
- include ViewWidgets
-
- def initialize(activity, unit_system, predecessor, successor)
+ def initialize(activity, unit_system)
@activity = activity
+ db = @activity.db
@unit_system = unit_system
- @predecessor = predecessor
- @successor = successor
- @output_dir = activity.db.cfg[:html_dir]
- @output_file = nil
- @doc = HTMLBuilder.new
+ views = db.views
+ views.current_page = nil
+
+ # Sort activities in reverse order so the newest one is considered the
+ # last report by the pagin buttons.
+ activities = db.activities.sort do |a1, a2|
+ a1.timestamp <=> a2.timestamp
+ end
+
+ pages = PagingButtons.new(activities.map do |a|
+ "#{a.fit_file[0..-5]}.html"
+ end, false)
+ pages.current_page = "#{@activity.fit_file[0..-5]}.html"
+
+ super("PostRunner Activity: #{@activity.name}", views, pages)
generate_html(@doc)
- write_file
+ write(File.join(db.cfg[:html_dir], pages.current_page))
end
private
def generate_html(doc)
- @report = ActivitySummary.new(@activity.fit_activity, @unit_system,
- { :name => @activity.name,
- :type => @activity.activity_type,
- :sub_type => @activity.activity_sub_type
- })
- @device_list = DeviceList.new(@activity.fit_activity)
- @user_profile = UserProfileView.new(@activity.fit_activity, @unit_system)
- @track_view = TrackView.new(@activity)
- @chart_view = ChartView.new(@activity, @unit_system)
-
- doc.html {
- head(doc)
- body(doc)
- }
- end
-
- def head(doc)
- doc.head {
- doc.meta({ 'http-equiv' => 'Content-Type',
- 'content' => 'text/html; charset=utf-8' })
- doc.meta({ 'name' => 'viewport',
- 'content' => 'width=device-width, ' +
- 'initial-scale=1.0, maximum-scale=1.0, ' +
- 'user-scalable=0' })
- doc.title("PostRunner Activity: #{@activity.name}")
- view_widgets_style(doc)
- @chart_view.head(doc)
- @track_view.head(doc)
- style(doc)
+ doc.head { doc.style(style) }
+ #doc.meta({ 'name' => 'viewport',
+ # 'content' => 'width=device-width, ' +
+ # 'initial-scale=1.0, maximum-scale=1.0, ' +
+ # 'user-scalable=0' })
+
+ body {
+ doc.body({ :onload => 'init()' }) {
+ # The main area with the 2 column layout.
+ doc.div({ :class => 'main' }) {
+ doc.div({ :class => 'left_col' }) {
+ ActivitySummary.new(@activity.fit_activity, @unit_system,
+ { :name => @activity.name,
+ :type => @activity.activity_type,
+ :sub_type => @activity.activity_sub_type
+ }).to_html(doc)
+ TrackView.new(@activity).to_html(doc)
+ DeviceList.new(@activity.fit_activity).to_html(doc)
+ UserProfileView.new(@activity.fit_activity, @unit_system).
+ to_html(doc)
+ }
+ doc.div({ :class => 'right_col' }) {
+ ChartView.new(@activity, @unit_system).to_html(doc)
+ }
+ }
+ }
}
end
- def style(doc)
- doc.style(<<EOT
+ def style
+ <<EOT
body {
font-family: verdana,arial,sans-serif;
margin: 0px;
@@ -93,37 +98,6 @@ body {
width: 600px;
}
EOT
- )
- end
-
- def body(doc)
- doc.body({ :onload => 'init()' }) {
- prev_page = @predecessor ? @predecessor.fit_file[0..-5] + '.html' : nil
- next_page = @successor ? @successor.fit_file[0..-5] + '.html' : nil
- titlebar(doc, nil, prev_page, 'index.html', next_page)
- # The main area with the 2 column layout.
- doc.div({ :class => 'main' }) {
- doc.div({ :class => 'left_col' }) {
- @report.to_html(doc)
- @track_view.div(doc)
- @device_list.to_html(doc)
- @user_profile.to_html(doc)
- }
- doc.div({ :class => 'right_col' }) {
- @chart_view.div(doc)
- }
- }
- footer(doc)
- }
- end
-
- def write_file
- @output_file = File.join(@output_dir, "#{@activity.fit_file[0..-5]}.html")
- begin
- File.write(@output_file, @doc.to_html)
- rescue IOError
- Log.fatal "Cannot write activity view file '#{@output_file}: #{$!}"
- end
end
end
diff --git a/lib/postrunner/ChartView.rb b/lib/postrunner/ChartView.rb
index 1aa6039..33e413d 100644
--- a/lib/postrunner/ChartView.rb
+++ b/lib/postrunner/ChartView.rb
@@ -9,14 +9,10 @@
# published by the Free Software Foundation.
#
-require 'postrunner/ViewWidgets'
-
module PostRunner
class ChartView
- include ViewWidgets
-
def initialize(activity, unit_system)
@activity = activity
@sport = activity.fit_activity.sessions[0].sport
@@ -24,17 +20,19 @@ module PostRunner
@empty_charts = {}
end
- def head(doc)
- [ 'jquery/jquery-2.1.1.min.js', 'flot/jquery.flot.js',
- 'flot/jquery.flot.time.js' ].each do |js|
- doc.script({ 'language' => 'javascript', 'type' => 'text/javascript',
- 'src' => js })
- end
- doc.style(style)
- doc.script(java_script)
- end
+ def to_html(doc)
+ doc.unique(:chartview_style) {
+ doc.head {
+ [ 'jquery/jquery-2.1.1.min.js', 'flot/jquery.flot.js',
+ 'flot/jquery.flot.time.js' ].each do |js|
+ doc.script({ 'language' => 'javascript',
+ 'type' => 'text/javascript', 'src' => js })
+ end
+ doc.style(style)
+ }
+ }
- def div(doc)
+ doc.script(java_script)
if @sport == 'running'
chart_div(doc, 'pace', "Pace (#{select_unit('min/km')})")
else
@@ -274,9 +272,9 @@ EOT
# Don't plot frame for graph without data.
return if @empty_charts[field]
- frame(doc, title) {
+ ViewFrame.new(title) {
doc.div({ 'id' => "#{field}_chart", 'class' => 'chart-placeholder'})
- }
+ }.to_html(doc)
end
def hover_function(chart_id, y_label, y_unit)
diff --git a/lib/postrunner/DeviceList.rb b/lib/postrunner/DeviceList.rb
index 3316dde..6ab63f2 100644
--- a/lib/postrunner/DeviceList.rb
+++ b/lib/postrunner/DeviceList.rb
@@ -3,7 +3,7 @@
#
# = DeviceList.rb -- PostRunner - Manage the data from your Garmin sport devices.
#
-# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
+# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@@ -12,22 +12,18 @@
require 'fit4ruby'
-require 'postrunner/ViewWidgets'
+require 'postrunner/ViewFrame'
module PostRunner
class DeviceList
- include ViewWidgets
-
def initialize(fit_activity)
@fit_activity = fit_activity
end
def to_html(doc)
- frame(doc, 'Devices') {
- devices.each { |d| d.to_html(doc) }
- }
+ ViewFrame.new('Devices', 600, devices).to_html(doc)
end
def to_s
diff --git a/lib/postrunner/FlexiTable.rb b/lib/postrunner/FlexiTable.rb
index 7385db7..8113cc1 100644
--- a/lib/postrunner/FlexiTable.rb
+++ b/lib/postrunner/FlexiTable.rb
@@ -3,7 +3,7 @@
#
# = FlexiTable.rb -- PostRunner - Manage the data from your Garmin sport devices.
#
-# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
+# Copyright (c) 2014, 2015 by Chris Schlaeger <cs@taskjuggler.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
@@ -252,6 +252,9 @@ module PostRunner
def to_html(doc)
index_table
+ doc.unique(:flexitable_style) {
+ doc.head { doc.style(style) }
+ }
doc.table(@html_attrs) {
@head_rows.each { |r| r.to_html(doc) }
@body_rows.each { |r| r.to_html(doc) }
@@ -318,6 +321,30 @@ module PostRunner
s + "\n"
end
+ def style
+ <<EOT
+.flexitable {
+ width: 100%;
+ border: 2px solid #545454;
+ border-collapse: collapse;
+ font-size:11pt;
+}
+.ft_head_row {
+ background-color: #DEDEDE
+}
+.ft_even_row {
+ background-color: #FCFCFC
+}
+.ft_odd_row {
+ background-color: #F1F1F1
+}
+.ft_cell {
+ border: 1px solid #CCCCCC;
+ padding: 1px 3px;
+}
+EOT
+ end
+
end
end
diff --git a/lib/postrunner/HTMLBuilder.rb b/lib/postrunner/HTMLBuilder.rb
index c9212fe..8c53f2f 100644
--- a/lib/postrunner/HTMLBuilder.rb
+++ b/lib/postrunner/HTMLBuilder.rb
@@ -19,18 +19,79 @@ module PostRunner
class HTMLBuilder
# Create a new HTMLBuilder object.
- def initialize
+ def initialize(title)
# This is the Nokogiri Document that will store all the data.
@doc = Nokogiri::HTML::Document.new
# We only need to keep a stack of the currently edited nodes so we know
# where we are in the node tree.
@node_stack = []
+ @tags = []
+
+ @html = create_node('html') {
+ @head = create_node('head') {
+ create_node('meta', { 'http-equiv' => 'Content-Type',
+ 'content' => 'text/html; charset=utf-8' })
+ create_node('title', title)
+ }
+ @body = create_node('body')
+ }
+ @node_stack << @html
+ @node_stack << @body
+ end
+
+ # Append nodes provided in block to head section of HTML document.
+ def head
+ @node_stack.push(@head)
+ yield if block_given?
+ unless @node_stack.pop == @head
+ raise ArgumentError, "node_stack corrupted in head"
+ end
+ end
+
+ # Append nodes provided in block to body section of HTML document.
+ def body(*args)
+ @node_stack.push(@body)
+ args.each do |arg|
+ if arg.is_a?(Hash)
+ arg.each { |k, v| @body[k] = v }
+ end
+ end
+ yield if block_given?
+ unless @node_stack.pop == @body
+ raise ArgumentError, "node_stack corrupted in body"
+ end
+ end
+
+ # Only execute the passed block if the provided tag has not been added
+ # yet.
+ def unique(tag)
+ unless @tags.include?(tag)
+ @tags << tag
+ yield if block_given?
+ end
end
# Any call to an undefined method will create a HTML node of the same
# name.
- def method_missing(method_name, *args)
- node = Nokogiri::XML::Node.new(method_name.to_s, @doc)
+ def method_missing(method_name, *args, &block)
+ create_node(method_name.to_s, *args, &block)
+ end
+
+ # Only needed to comply with style guides. This all calls to unknown
+ # method will be handled properly. So, we always return true.
+ def respond_to?(method)
+ true
+ end
+
+ # Dump the HTML document as HTML formatted String.
+ def to_html
+ @doc.to_html
+ end
+
+ private
+
+ def create_node(name, *args)
+ node = Nokogiri::XML::Node.new(name, @doc)
if (parent = @node_stack.last)
parent.add_child(node)
else
@@ -52,19 +113,6 @@ module PostRunner
@node_stack.pop
end
- # Only needed to comply with style guides. This all calls to unknown
- # method will be handled properly. So, we always return true.
- def respond_to?(method)
- true
- end
-
- # Dump the HTML document as HTML formatted String.
- def to_html
- @doc.to_html
- end
-
- private
-
def add_child(parent, node)
if parent
parent.add_child(node)
diff --git a/lib/postrunner/NavButtonRow.rb b/lib/postrunner/NavButtonRow.rb
new file mode 100644
index 0000000..7e1ea06
--- /dev/null
+++ b/lib/postrunner/NavButtonRow.rb
@@ -0,0 +1,103 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = NavButtonRow.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/HTMLBuilder'
+
+module PostRunner
+
+ # Auxilliary class that stores the name of an icon file and a URL as a
+ # String. It is used to describe a NavButtonRow button.
+ class NavButtonDef < Struct.new(:icon, :url)
+ end
+
+ # A NavButtonRow is a row of buttons used to navigate between HTML pages.
+ class NavButtonRow
+
+ # A class to store the icon and URL of a button in the NavButtonRow
+ # objects.
+ class Button
+
+ # Create a Button object.
+ # @param icon [String] File name of the icon file
+ # @param url [String] URL of the page to change to
+ def initialize(icon, url = nil)
+ @icon = icon
+ @url = url
+ end
+
+ # Add the object as HTML Elements to the document.
+ # @param doc [HTMLBuilder] XML Document
+ def to_html(doc)
+ if @url
+ doc.a({ :href => @url }) {
+ doc.img({ :src => "icons/#{@icon}", :class => 'active_button' })
+ }
+ else
+ doc.img({ :src => "icons/#{@icon}", :class => 'inactive_button' })
+ end
+ end
+
+ end
+
+ # Create a new NavButtonRow object.
+ # @param float [String, Nil] specifies if the HTML representation should
+ # be a floating object that floats left or right.
+ def initialize(float = nil)
+ unless float.nil? || %w( left right ).include?(float)
+ raise ArgumentError "float argument must be nil, 'left' or 'right'"
+ end
+
+ @float = float
+ @buttons = []
+ end
+
+ # Add a new button to the NavButtonRow object.
+ # @param icon [String] File name of the icon file
+ # @param url [String] URL of the page to change to
+ def addButton(icon, url = nil)
+ @buttons << Button.new(icon, url)
+ end
+
+ # Add the object as HTML Elements to the document.
+ # @param doc [HTMLBuilder] XML Document
+ def to_html(doc)
+ doc.unique(:nav_button_row_style) {
+ doc.head { doc.style(style) }
+ }
+ doc.div({ :class => 'nav_button_row',
+ :style => "width: #{@buttons.length * (32 + 10)}px; " +
+ "#{@float ? "float: #{@float};" :
+ 'margin-left: auto; margin-right: auto'}"}) {
+ @buttons.each { |btn| btn.to_html(doc) }
+ }
+ end
+
+ private
+
+ def style
+ <<"EOT"
+.nav_button_row {
+ padding: 3px 30px;
+}
+.active_button {
+ padding: 5px;
+}
+.inactive_button {
+ padding: 5px;
+ opacity: 0.4;
+}
+EOT
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/PagingButtons.rb b/lib/postrunner/PagingButtons.rb
new file mode 100644
index 0000000..aa1f5f2
--- /dev/null
+++ b/lib/postrunner/PagingButtons.rb
@@ -0,0 +1,77 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = PagingButtons.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/NavButtonRow'
+
+module PostRunner
+
+ # A class to generate a set of forward/backward buttons for an HTML page. It
+ # can also include jump to first/last buttons.
+ class PagingButtons
+
+ # Create a new PagingButtons object.
+ # @param page_urls [Array of String] Sorted list of all possible pages
+ # @param end_buttons [Boolean] If true jump to first/last buttons are
+ # included
+ def initialize(page_urls, end_buttons = true)
+ if page_urls.empty?
+ raise ArgumentError.new("'page_urls' must not be empty")
+ end
+ @pages = page_urls
+ @current_page_index = 0
+ @end_buttons = end_buttons
+ end
+
+ # Return the URL of the current page
+ def current_page
+ @pages[@current_page_index]
+ end
+
+ # Set the URL for the current page. It must be included in the URL set
+ # passed at creation time. The forward/backward links will be derived from
+ # the setting of the current page.
+ # @param page_url [String] URL of the page
+ def current_page=(page_url)
+ unless (@current_page_index = @pages.index(page_url))
+ raise ArgumentError.new("URL #{page_url} is not a known page URL")
+ end
+ end
+
+ # Iterate over all buttons. A NavButtonDef object is passed to the block
+ # that contains the icon and URL for the button. If no URL is set, the
+ # button is inactive.
+ def each
+ %w( first back forward last ).each do |button_name|
+ button = NavButtonDef.new
+ button.icon = button_name + '.png'
+ button.url =
+ case button_name
+ when 'first'
+ @current_page_index == 0 || !@end_buttons ? nil : @pages.first
+ when 'back'
+ @current_page_index == 0 ? nil :
+ @pages[@current_page_index - 1]
+ when 'forward'
+ @current_page_index == @pages.length - 1 ? nil :
+ @pages[@current_page_index + 1]
+ when 'last'
+ @current_page_index == @pages.length - 1 ||
+ !@end_buttons ? nil : @pages.last
+ end
+
+ yield(button)
+ end
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/PersonalRecords.rb b/lib/postrunner/PersonalRecords.rb
index aba2f6a..7f69529 100644
--- a/lib/postrunner/PersonalRecords.rb
+++ b/lib/postrunner/PersonalRecords.rb
@@ -15,6 +15,8 @@ require 'yaml'
require 'fit4ruby'
require 'postrunner/BackedUpFile'
+require 'postrunner/RecordListPageView'
+require 'postrunner/ActivityLink'
module PostRunner
@@ -89,7 +91,8 @@ module PostRunner
secsToHMS(@duration),
speedToPace(@distance / @duration) ]) +
[ @activity.db.ref_by_fit_file(@activity.fit_file),
- @activity.name, @start_time.strftime("%Y-%m-%d") ])
+ ActivityLink.new(@activity, false),
+ @start_time.strftime("%Y-%m-%d") ])
end
end
@@ -171,6 +174,16 @@ module PostRunner
def to_s
return '' if empty?
+ generate_table.to_s + "\n"
+ end
+
+ def to_html(doc)
+ generate_table.to_html(doc)
+ end
+
+ private
+
+ def generate_table
t = FlexiTable.new
t.head
t.row([ 'Record', 'Time/Dist.', 'Avg. Pace', 'Ref.', 'Activity',
@@ -192,13 +205,17 @@ module PostRunner
records.sort { |r1, r2| r1.distance <=> r2.distance }.each do |r|
r.to_table_row(t)
end
- t.to_s + "\n"
+
+ t
end
+
end
class SportRecords
+ attr_reader :sport, :all_time, :yearly
+
def initialize(sport)
@sport = sport
@all_time = RecordSet.new(@sport, nil)
@@ -251,6 +268,22 @@ module PostRunner
str
end
+ def to_html(doc)
+ return nil if empty?
+
+ doc.div {
+ doc.h3('All-time records')
+ @all_time.to_html(doc)
+ @yearly.values.sort{ |r1, r2| r2.year <=> r1.year }.each do |record|
+ puts record.year
+ unless record.empty?
+ doc.h3("Records of #{record.year}")
+ record.to_html(doc)
+ end
+ end
+ }
+ end
+
end
def initialize(activities)
@@ -286,6 +319,16 @@ module PostRunner
def sync
save_records
+
+ non_empty_records = @sport_records.select { |s, r| !r.empty? }
+ max = non_empty_records.length
+ i = 0
+ non_empty_records.each do |sport, record|
+ output_file = File.join(@activities.cfg[:html_dir],
+ "records-#{i}.html")
+ RecordListPageView.new(@activities, record, max, i).
+ write(output_file)
+ end
end
def to_s
diff --git a/lib/postrunner/RecordListPageView.rb b/lib/postrunner/RecordListPageView.rb
new file mode 100644
index 0000000..f1de004
--- /dev/null
+++ b/lib/postrunner/RecordListPageView.rb
@@ -0,0 +1,69 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = RecordListPageView.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'fit4ruby'
+
+require 'postrunner/FlexiTable'
+require 'postrunner/View'
+require 'postrunner/ViewFrame'
+require 'postrunner/ViewButtons'
+require 'postrunner/PagingButtons'
+
+module PostRunner
+
+ # Generates an HTML page with all personal records for a particular sport
+ # type.
+ class RecordListPageView < View
+
+ include Fit4Ruby::Converters
+
+ # Create a RecordListPageView object.
+ # @param db [ActivityDB] Activity database
+ # @param records [PersonalRecords] Database with personal records
+ # @param page_count [Fixnum] Number of total pages
+ # @param page_index [Fixnum] Index of the page
+ def initialize(db, records, page_count, page_index)
+ @db = db
+ @unit_system = @db.cfg[:unit_system]
+ @records = records
+
+ views = @db.views
+ views.current_page = "records-0.html"
+
+ pages = PagingButtons.new((0..(page_count - 1)).map do |i|
+ "records-#{i}.html"
+ end)
+ pages.current_page =
+ "records-#{page_index}.html"
+
+ @sport_name = Activity::ActivityTypes[@records.sport]
+ super("#{@sport_name} Records", views, pages)
+
+ body {
+ frame_width = 800
+
+ @doc.div({ :class => 'main' }) {
+ ViewFrame.new("All-time #{@sport_name} Records",
+ frame_width, @records.all_time).to_html(@doc)
+
+ @records.yearly.each do |year, record|
+ next if record.empty?
+ ViewFrame.new("#{year} #{@sport_name} Records",
+ frame_width, record).to_html(@doc)
+ end
+ }
+ }
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/TrackView.rb b/lib/postrunner/TrackView.rb
index 7171706..fc7bc21 100644
--- a/lib/postrunner/TrackView.rb
+++ b/lib/postrunner/TrackView.rb
@@ -12,37 +12,35 @@
require 'fit4ruby'
-require 'postrunner/ViewWidgets'
+require 'postrunner/ViewFrame'
module PostRunner
class TrackView
- include ViewWidgets
-
def initialize(activity)
@activity = activity
@session = @activity.fit_activity.sessions[0]
@has_geo_data = @session.has_geo_data?
end
- def head(doc)
+ def to_html(doc)
return unless @has_geo_data
- doc.link({ 'rel' => 'stylesheet',
- 'href' => 'openlayers/theme/default/style.css',
- 'type' => 'text/css' })
- doc.style(style)
- doc.script({ 'src' => 'openlayers/OpenLayers.js' })
- doc.script(java_script)
- end
-
- def div(doc)
- return unless @has_geo_data
+ doc.head {
+ doc.unique(:trackview_style) {
+ doc.style(style)
+ doc.link({ 'rel' => 'stylesheet',
+ 'href' => 'openlayers/theme/default/style.css',
+ 'type' => 'text/css' })
+ doc.script({ 'src' => 'openlayers/OpenLayers.js' })
+ }
+ doc.script(java_script)
+ }
- frame(doc, 'Map') {
+ ViewFrame.new('Map', 600) {
doc.div({ 'id' => 'map', 'class' => 'trackmap' })
- }
+ }.to_html(doc)
end
private
diff --git a/lib/postrunner/UserProfileView.rb b/lib/postrunner/UserProfileView.rb
index 3ff4341..c89216b 100644
--- a/lib/postrunner/UserProfileView.rb
+++ b/lib/postrunner/UserProfileView.rb
@@ -12,14 +12,12 @@
require 'fit4ruby'
-require 'postrunner/ViewWidgets'
+require 'postrunner/ViewFrame'
module PostRunner
class UserProfileView
- include ViewWidgets
-
def initialize(fit_activity, unit_system)
@fit_activity = fit_activity
@unit_system = unit_system
@@ -28,9 +26,7 @@ module PostRunner
def to_html(doc)
return nil if @fit_activity.user_profiles.empty?
- frame(doc, 'User Profile') {
- profile.to_html(doc)
- }
+ ViewFrame.new('User Profile', 600, profile).to_html(doc)
end
def to_s
diff --git a/lib/postrunner/View.rb b/lib/postrunner/View.rb
new file mode 100644
index 0000000..acfd258
--- /dev/null
+++ b/lib/postrunner/View.rb
@@ -0,0 +1,97 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = View.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/HTMLBuilder'
+require 'postrunner/ViewTop'
+require 'postrunner/ViewBottom'
+
+module PostRunner
+
+ # Base class for all generated HTML pages.
+ class View
+
+ attr_reader :doc
+
+ # Create a new View object.
+ # @param title [String] The title of the HTML page
+ # @param views [ViewButtons] List of all cross referenced View objects
+ # @param pages [PagingButtons] List of all pages of this View
+ def initialize(title, views, pages)
+ @doc = HTMLBuilder.new(title)
+ @views = views
+ @pages = pages
+
+ @doc.unique(:view_style) {
+ style
+ }
+ end
+
+ # Create the body section of the HTML document.
+ def body
+ ViewTop.new(@views, @pages).to_html(@doc)
+ yield if block_given?
+ ViewBottom.new.to_html(@doc)
+
+ self
+ end
+
+ # Convert the View into an HTML document.
+ def to_html
+ @doc.to_html
+ end
+
+ # Write the HTML document to a file
+ # @param file_name [String] Name of the file to write
+ def write(file_name)
+ begin
+ File.write(file_name, to_html)
+ rescue IOError
+ Log.fatal "Cannot write file '#{file_name}: #{$!}"
+ end
+ end
+
+ private
+
+ def style
+ @doc.head {
+ @doc.style(<<"EOT"
+body {
+ font-family: verdana,arial,sans-serif;
+ margin: 0px;
+}
+.flexitable {
+ width: 100%;
+ border: 2px solid #545454;
+ border-collapse: collapse;
+ font-size:11pt;
+}
+.ft_head_row {
+ background-color: #DEDEDE
+}
+.ft_even_row {
+ background-color: #FCFCFC
+}
+.ft_odd_row {
+ background-color: #F1F1F1
+}
+.ft_cell {
+ border: 1px solid #CCCCCC;
+ padding: 1px 3px;
+}
+EOT
+ )
+ }
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/ViewBottom.rb b/lib/postrunner/ViewBottom.rb
new file mode 100644
index 0000000..3812919
--- /dev/null
+++ b/lib/postrunner/ViewBottom.rb
@@ -0,0 +1,54 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = ViewBottom.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/HTMLBuilder'
+require 'postrunner/version'
+
+module PostRunner
+
+ # This class generates the footer of a HTML page.
+ class ViewBottom
+
+ # Generate the HTML code to that describes the foot section.
+ # @param doc [HTMLBuilder] Reference to the HTML document to add to.
+ def to_html(doc)
+ doc.unique(:viewbottom_style) {
+ doc.head { doc.style(style) }
+ }
+ doc.div({ :class => 'footer' }){
+ doc.hr
+ doc.div({ :class => 'copyright' }) {
+ doc.text("Generated by ")
+ doc.a('PostRunner',
+ { :href => 'https://github.com/scrapper/postrunner' })
+ doc.text(" #{VERSION} on #{Time.now}")
+ }
+ }
+ end
+
+ private
+
+ def style
+ <<EOT
+.footer {
+ clear: both;
+ width: 100%;
+ height: 30px;
+ padding: 15px 0px;
+ text-align: center;
+ font-size: 9pt;
+}
+EOT
+ end
+ end
+
+end
diff --git a/lib/postrunner/ViewButtons.rb b/lib/postrunner/ViewButtons.rb
new file mode 100644
index 0000000..4c95162
--- /dev/null
+++ b/lib/postrunner/ViewButtons.rb
@@ -0,0 +1,68 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = ViewButtons.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+module PostRunner
+
+ # This class generates a simple icon menue to select from a set of HTML
+ # pages (called views). The current page is represented as an inactive icon.
+ # All other icons are buttons that contain links to other pages.
+ class ViewButtons
+
+ # Create a ViewButtons object.
+ # @params views [Array of NavButtonDef] icons and URLs for all pages.
+ def initialize(views)
+ if views.empty?
+ raise ArgumentError.new("'views' must not be empty")
+ end
+ @views = views
+ self.current_page = views[0].url
+ end
+
+ # Get the URL of the current page
+ # @return [String]
+ def current_page
+ @current_view_url
+ end
+
+ # Set the the current page.
+ # @param page_url [String] URL of the current page. This must either be
+ # nil or a URL in the predefined set.
+ def current_page=(page_url)
+ unless page_url
+ @current_view_url = nil
+ return
+ end
+
+ if (current = @views.find { |v| v.url == page_url })
+ @current_view_url = current.url
+ else
+ raise ArgumentError.new("#{page_url} is not a URL of a known view")
+ end
+ end
+
+ # Iterate over all buttons. A NavButtonDef object is passed to the block
+ # that contains the icon and URL for the button. If no URL is set, the
+ # button is inactive.
+ def each
+ @views.each do |view|
+ view = view.clone
+ if @current_view_url == view.url
+ view.url = nil
+ end
+ yield(view)
+ end
+
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/ViewFrame.rb b/lib/postrunner/ViewFrame.rb
new file mode 100644
index 0000000..863ad2a
--- /dev/null
+++ b/lib/postrunner/ViewFrame.rb
@@ -0,0 +1,93 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = ViewFrame.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+module PostRunner
+
+ # Creates an HTML frame around the passed object or HTML block.
+ class ViewFrame
+
+ # Create a ViewFrame object.
+ # @param title [String] Title/heading of the framed box
+ # @param width [Fixnum or nil] Width of the frame. Use nil to set no
+ # width.
+ # @param content [Any object that respons to to_html] Object to frame
+ # @param &block [HTMLBuilder actions]
+ def initialize(title, width = 600, content = nil, &block)
+ @title = title
+ @content = content
+ @block = block
+ @width = width
+ end
+
+ # Generate the HTML code for the frame and the enclosing content.
+ # @param doc [HTMLBuilder] HTML document
+ def to_html(doc)
+ doc.unique(:viewframe_style) {
+ # Add the necessary style sheet snippets to the document head.
+ doc.head { doc.style(style) }
+ }
+
+ attr = { 'class' => 'widget_frame' }
+ attr['style'] = "width: #{@width}px" if @width
+ doc.div(attr) {
+ doc.div({ 'class' => 'widget_frame_title' }) {
+ doc.b(@title)
+ }
+ doc.div {
+ # The @content holds an object that must respond to to_html to
+ # generate the HTML code.
+ if @content
+ if @content.is_a?(Array)
+ @content.each { |c| c.to_html(doc) }
+ else
+ @content.to_html(doc)
+ end
+ end
+ # The block generates HTML code directly
+ @block.yield if @block
+ }
+ }
+ end
+
+ private
+
+ def style
+ <<EOT
+.widget_frame {
+ box-sizing: border-box;
+ padding: 10px 15px 15px 15px;
+ margin: 15px auto 15px auto;
+ border: 1px solid #ddd;
+ background: #fff;
+ background: linear-gradient(#f6f6f6 0, #fff 50px);
+ background: -o-linear-gradient(#f6f6f6 0, #fff 50px);
+ background: -ms-linear-gradient(#f6f6f6 0, #fff 50px);
+ background: -moz-linear-gradient(#f6f6f6 0, #fff 50px);
+ background: -webkit-linear-gradient(#f6f6f6 0, #fff 50px);
+ box-shadow: 0 3px 10px rgba(0,0,0,0.15);
+ -o-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+ -ms-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+ -moz-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+ -webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+}
+.widget_frame_title {
+ font-size:13pt;
+ padding-bottom: 5px;
+ text-align: left;
+}
+EOT
+ end
+
+ end
+
+end
+
diff --git a/lib/postrunner/ViewTop.rb b/lib/postrunner/ViewTop.rb
new file mode 100644
index 0000000..c79d0ea
--- /dev/null
+++ b/lib/postrunner/ViewTop.rb
@@ -0,0 +1,80 @@
+#!/usr/bin/env ruby -w
+# encoding: UTF-8
+#
+# = ViewTop.rb -- PostRunner - Manage the data from your Garmin sport devices.
+#
+# Copyright (c) 2015 by Chris Schlaeger <cs@taskjuggler.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+
+require 'postrunner/HTMLBuilder'
+require 'postrunner/NavButtonRow'
+
+module PostRunner
+
+ # This class generates the top part of the HTML page. It contains the logo
+ # and the menu and navigation buttons.
+ class ViewTop
+
+ # Create a ViewTop object.
+ # @param views [Array of NavButtonDef] icons and URLs for views
+ # @param pages [Array of NavButtonDef] Full list of pages of this view.
+ def initialize(views, pages)
+ @views = views
+ @pages = pages
+ end
+
+ # Generate the HTML code to that describes the top section.
+ # @param doc [HTMLBuilder] Reference to the HTML document to add to.
+ def to_html(doc)
+ doc.unique(:viewtop_style) {
+ doc.head { doc.style(style) }
+ }
+ doc.div({ :class => 'titlebar' }) {
+ doc.div('PostRunner', { :class => 'title' })
+
+ page_selector = NavButtonRow.new('right')
+ @pages.each do |p|
+ page_selector.addButton(p.icon, p.url)
+ end
+ page_selector.to_html(doc)
+
+ view_selector = NavButtonRow.new
+ @views.each do |v|
+ view_selector.addButton(v.icon, v.url)
+ end
+ view_selector.to_html(doc)
+ }
+ end
+
+ private
+
+ def style
+ <<EOT
+.titlebar {
+ width: 100%;
+ height: 50px;
+ margin: 0px;
+ background: linear-gradient(#7FA1FF 0, #002EAC 50px);
+}
+.title {
+ float: left;
+ font-size: 24pt;
+ font-style: italic;
+ font-weight: bold;
+ color: #F8F8F8;
+ text-shadow: -1px -1px 0 #5C5C5C,
+ 1px -1px 0 #5C5C5C,
+ -1px 1px 0 #5C5C5C,
+ 1px 1px 0 #5C5C5C;
+ padding: 3px 30px;
+}
+EOT
+ end
+
+ end
+
+end
diff --git a/lib/postrunner/ViewWidgets.rb b/lib/postrunner/ViewWidgets.rb
deleted file mode 100644
index b4b4207..0000000
--- a/lib/postrunner/ViewWidgets.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-#!/usr/bin/env ruby -w
-# encoding: UTF-8
-#
-# = ViewWidgets.rb -- PostRunner - Manage the data from your Garmin sport devices.
-#
-# Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of version 2 of the GNU General Public License as
-# published by the Free Software Foundation.
-#
-
-module PostRunner
-
- module ViewWidgets
-
- def view_widgets_style(doc)
- doc.style(<<EOT
-.titlebar {
- width: 100%;
- height: 50px;
- margin: 0px;
- background: linear-gradient(#7FA1FF 0, #002EAC 50px);
-}
-.title {
- float: left;
- font-size: 24pt;
- font-style: italic;
- font-weight: bold;
- color: #F8F8F8;
- text-shadow: -1px -1px 0 #5C5C5C,
- 1px -1px 0 #5C5C5C,
- -1px 1px 0 #5C5C5C,
- 1px 1px 0 #5C5C5C;
- padding: 3px 30px;
-}
-.navigator {
- float: right;
- padding: 3px 30px;
-}
-.active_button {
- padding: 5px;
-}
-.inactive_button {
- padding: 5px;
- opacity: 0.4;
-}
-.widget_frame {
- box-sizing: border-box;
- width: 600px;
- padding: 10px 15px 15px 15px;
- margin: 15px auto 15px auto;
- border: 1px solid #ddd;
- background: #fff;
- background: linear-gradient(#f6f6f6 0, #fff 50px);
- background: -o-linear-gradient(#f6f6f6 0, #fff 50px);
- background: -ms-linear-gradient(#f6f6f6 0, #fff 50px);
- background: -moz-linear-gradient(#f6f6f6 0, #fff 50px);
- background: -webkit-linear-gradient(#f6f6f6 0, #fff 50px);
- box-shadow: 0 3px 10px rgba(0,0,0,0.15);
- -o-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
- -ms-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
- -moz-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
- -webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
-}
-.widget_frame_title {
- font-size:13pt;
- padding-bottom: 5px;
- text-align: left;
-}
-.flexitable {
- width: 100%;
- border: 2px solid #545454;
- border-collapse: collapse;
- font-size:11pt;
-}
-.ft_head_row {
- background-color: #DEDEDE
-}
-.ft_even_row {
- background-color: #FCFCFC
-}
-.ft_odd_row {
- background-color: #F1F1F1
-}
-.ft_cell {
- border: 1px solid #CCCCCC;
- padding: 1px 3px;
-}
-.footer {
- clear: both;
- width: 100%;
- height: 30px;
- padding: 15px;
- text-align: center;
- font-size: 9pt;
-}
-EOT
- )
- end
-
- def frame(doc, title)
- doc.div({ 'class' => 'widget_frame' }) {
- doc.div({ 'class' => 'widget_frame_title' }) {
- doc.b(title)
- }
- doc.div {
- yield if block_given?
- }
- }
- end
-
- def titlebar(doc, first_page = nil, prev_page = nil, home_page = nil,
- next_page = nil, last_page = nil)
- # The top title bar.
- doc.div({ :class => 'titlebar' }) {
- doc.div('PostRunner', { :class => 'title' })
- doc.div({ :class => 'navigator' }) {
- button(doc, first_page, 'first.png')
- button(doc, prev_page, 'back.png')
- button(doc, home_page, 'home.png')
- button(doc, next_page, 'forward.png')
- button(doc, last_page, 'last.png')
- }
- }
- end
-
- def button(doc, link, icon)
- if link
- doc.a({ :href => link }) {
- doc.img({ :src => "icons/#{icon}", :class => 'active_button' })
- }
- else
- doc.img({ :src => "icons/#{icon}", :class => 'inactive_button' })
- end
- end
-
- def footer(doc)
- doc.div({ :class => 'footer' }){
- doc.hr
- doc.div({ :class => 'copyright' }) {
- doc.text("Generated by ")
- doc.a('PostRunner',
- { :href => 'https://github.com/scrapper/postrunner' })
- doc.text(" #{VERSION} on #{Time.now}")
- }
- }
- end
-
- end
-
-end
-