Browse Source

Added conference list page, administration tools, and re-designed conference administration

development
Godwin 8 years ago
parent
commit
1dc608bf58
  1. 17
      Rakefile
  2. 84
      app/assets/images/Facebook_icon_2013.svg
  3. BIN
      app/assets/images/admin.jpg
  4. 1
      app/assets/images/admin/administrators.svg
  5. BIN
      app/assets/images/admin/broadcast.png
  6. 1
      app/assets/images/admin/broadcast.svg
  7. BIN
      app/assets/images/admin/dates.png
  8. 1
      app/assets/images/admin/dates.svg
  9. BIN
      app/assets/images/admin/description.png
  10. 1
      app/assets/images/admin/description.svg
  11. BIN
      app/assets/images/admin/events.png
  12. 1
      app/assets/images/admin/events.svg
  13. BIN
      app/assets/images/admin/housing.png
  14. 1
      app/assets/images/admin/housing.svg
  15. BIN
      app/assets/images/admin/locations.png
  16. 1
      app/assets/images/admin/locations.svg
  17. BIN
      app/assets/images/admin/meals.png
  18. 1
      app/assets/images/admin/meals.svg
  19. BIN
      app/assets/images/admin/payment.png
  20. 1
      app/assets/images/admin/payment.svg
  21. 1
      app/assets/images/admin/payment_message.svg
  22. 1
      app/assets/images/admin/paypal.svg
  23. BIN
      app/assets/images/admin/poster.png
  24. 1
      app/assets/images/admin/poster.svg
  25. BIN
      app/assets/images/admin/providers.png
  26. 1
      app/assets/images/admin/providers.svg
  27. 1
      app/assets/images/admin/publish_schedule.svg
  28. 1
      app/assets/images/admin/registration_status.svg
  29. BIN
      app/assets/images/admin/registrations.png
  30. 1
      app/assets/images/admin/registrations.svg
  31. BIN
      app/assets/images/admin/schedule.png
  32. 1
      app/assets/images/admin/schedule.svg
  33. BIN
      app/assets/images/admin/stats.png
  34. 1
      app/assets/images/admin/stats.svg
  35. 1
      app/assets/images/admin/suggested_amounts.svg
  36. BIN
      app/assets/images/admin/workshop_times.png
  37. 1
      app/assets/images/admin/workshop_times.svg
  38. BIN
      app/assets/images/conferences.jpg
  39. 0
      app/assets/images/facebook.png
  40. 1
      app/assets/images/facebook.svg
  41. 0
      app/assets/images/github.png
  42. 1
      app/assets/images/github.svg
  43. 2
      app/assets/images/logo-text.svg
  44. 2
      app/assets/images/logo.svg
  45. 3
      app/assets/images/octicat.svg
  46. 15
      app/assets/javascripts/editor.js
  47. 31
      app/assets/javascripts/filefield.js
  48. 4
      app/assets/javascripts/jquery.min.js
  49. 11
      app/assets/javascripts/main.js
  50. 117
      app/assets/javascripts/map.js
  51. 26
      app/assets/javascripts/userfield.js
  52. 812
      app/assets/stylesheets/_application.scss
  53. 11
      app/assets/stylesheets/_settings.scss
  54. 4
      app/assets/stylesheets/bumbleberry-settings.json
  55. 36
      app/controllers/admin_controller.rb
  56. 127
      app/controllers/application_controller.rb
  57. 1208
      app/controllers/conference_administration_controller.rb
  58. 1447
      app/controllers/conferences_controller.rb
  59. 355
      app/controllers/workshops_controller.rb
  60. 298
      app/helpers/application_helper.rb
  61. 77
      app/models/city.rb
  62. 9
      app/models/city_cache.rb
  63. 79
      app/models/conference.rb
  64. 4
      app/models/conference_administrator.rb
  65. 2
      app/models/conference_registration.rb
  66. 12
      app/models/organization.rb
  67. 5
      app/models/user.rb
  68. 6
      app/uploaders/avatar_uploader.rb
  69. 24
      app/views/admin/new.html.haml
  70. 4
      app/views/application/_header.html.haml
  71. 22
      app/views/application/home.html.haml
  72. 41
      app/views/conference_administration/_administrators.html.haml
  73. 23
      app/views/conference_administration/_broadcast.html.haml
  74. 0
      app/views/conference_administration/_broadcast_sent.html.haml
  75. 17
      app/views/conference_administration/_dates.html.haml
  76. 5
      app/views/conference_administration/_description.html.haml
  77. 41
      app/views/conference_administration/_events.html.haml
  78. 11
      app/views/conference_administration/_hosts_table.html.haml
  79. 10
      app/views/conference_administration/_housing.html.haml
  80. 42
      app/views/conference_administration/_locations.html.haml
  81. 35
      app/views/conference_administration/_meals.html.haml
  82. 6
      app/views/conference_administration/_payment_message.html.haml
  83. 8
      app/views/conference_administration/_paypal.html.haml
  84. 5
      app/views/conference_administration/_poster.html.haml
  85. 2
      app/views/conference_administration/_providers.html.haml
  86. 8
      app/views/conference_administration/_publish_schedule.html.haml
  87. 5
      app/views/conference_administration/_registration_status.html.haml
  88. 17
      app/views/conference_administration/_registrations.html.haml
  89. 85
      app/views/conference_administration/_schedule.html.haml
  90. 46
      app/views/conference_administration/_select_guest_table.html.haml
  91. 0
      app/views/conference_administration/_select_workshop_table.html.haml
  92. 21
      app/views/conference_administration/_stats.html.haml
  93. 8
      app/views/conference_administration/_suggested_amounts.html.haml
  94. 19
      app/views/conference_administration/_workshop_times.html.haml
  95. 27
      app/views/conference_administration/administration.html.haml
  96. 38
      app/views/conference_administration/administration_step.html.haml
  97. 34
      app/views/conferences/_conference.html.haml
  98. 10
      app/views/conferences/_header.html.haml
  99. 2
      app/views/conferences/_page_header.html.haml
  100. 22
      app/views/conferences/admin/_broadcast.html.haml

17
Rakefile

@ -4,3 +4,20 @@
require File.expand_path('../config/application', __FILE__)
BikeBike::Application.load_tasks
task regenerate_images: :environment do
{
conference: [ :cover, :poster ],
organization: [ :logo, :avatar, :cover ]
}.each do | model_class, attributes |
Object.const_get(model_class.to_s.titlecase).all.each do | model |
attributes.each do | attribute |
uploader = model.send(attribute)
if uploader.present?
puts "Regenerating #{model_class}.#{attribute} = #{uploader.url}"
uploader.recreate_versions!
end
end
end
end
end

84
app/assets/images/Facebook_icon_2013.svg

@ -1,84 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1000"
height="1000"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="New document 1">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="1268.2181"
inkscape:cy="-8.1858472"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-left="0.5"
fit-margin-bottom="0.5"
fit-margin-top="0.5"
fit-margin-right="0.5"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid2996"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-39.499999,287.13782)">
<g
id="g3005"
transform="matrix(1.7404181,0,0,1.7404181,-29.616725,-527.44586)">
<path
sodipodi:nodetypes="ssssscccssss"
inkscape:connector-curvature="0"
id="rect3000"
d="m 71,138.36218 512,0 c 17.174,0 31,13.826 31,31 l 0,512 c 0,17.174 -13.826,31 -31,31 l -146.5,0 -45.81978,-37.88194 -44.18022,37.88194 -275.5,0 c -17.174,0 -31,-13.826 -31,-31 l 0,-512 c 0,-17.174 13.826,-31 31,-31 z"
style="fill:#3b579d;fill-opacity:1;stroke:none" />
<path
sodipodi:nodetypes="ccccccccccccccccc"
inkscape:connector-curvature="0"
id="path3002"
d="m 346.5,712.36218 0,-222.5 -75,0 0,-86.5 75,0 0,-66 c 0,-69.18633 42.89263,-112.18866 110.45353,-112.18866 40.67053,0 68.04647,3.18866 68.04647,3.18866 l 0,78 -45.82143,0 c -29.03699,0 -42.67857,10.21289 -42.67857,41 l 0,56 85.5,0 -11,86.5 -74.5,0 0,222.5 z"
style="fill:#ffffff;stroke:none" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/assets/images/admin.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

1
app/assets/images/admin/administrators.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="0 0 100 125"><path d="M32.5 30.1a4.63 4.63 0 1 1-4.62-4.6 4.62 4.62 0 0 1 4.62 4.6zm58.17 42.73V91H71.3V81h-9.9V70.64h-9.88v-6a29.28 29.28 0 1 1 14.7-16.25zm-4 1.66L61.6 49.23l.4-1.15a25.4 25.4 0 1 0-9.6 11.46l3.1-2v9.08h9.88V77h9.88v10h11.4z"/></svg>

After

Width:  |  Height:  |  Size: 320 B

BIN
app/assets/images/admin/broadcast.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

1
app/assets/images/admin/broadcast.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 40"><path d="M0 25.5h7.7v5.7l7-5.7H32V.8H0v24.7zM2 2.8h28v20.7H14l-.5.4-3.8 3v-3.7H2V2.8z"/><path d="M8.8 4.7H17v2H8.8zm0 3.7h11.8v2H8.8zm0 3.6h14.5v2H8.8zm0 3.8h11.8v2H8.8zm0 3.6h8.6v2H8.8z"/></svg>

After

Width:  |  Height:  |  Size: 255 B

BIN
app/assets/images/admin/dates.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

1
app/assets/images/admin/dates.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1" viewBox="0 0 62 72.5"><path d="M0 0v58h62V0H0zm12 56H2V46h10v10zm12 0H14V46h10v10zm12 0H26V46h10v10zm12 0H38V46h10v10zm12 0H50V46h10v10zm0-36v2H50v10h10v12H50V34h-2v10H38V34h-2v10H26V34h-2v10H14V34h-2v10H2V32h10V22H2V10h10v10h2V10h10v10h2V10h10v10h2V10h10v10h2V10h10v10z"/><path d="M14 22h10v10H14zm12 0h10v10H26zm12 0h10v10H38z"/></svg>

After

Width:  |  Height:  |  Size: 389 B

BIN
app/assets/images/admin/description.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

1
app/assets/images/admin/description.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path d="M76 24.6l-8-8H24v67h52v-59zM68.5 20l4 4h-4v-4zM26 81.4v-63h40.5V26H74v55.5H26z"/><path d="M30 24h20v2H30zm0 5h40v2H30zm0 5h25v2H30zm27.5 0H70v2H57.5zM30 39h40v2H30zm0 5h15v2H30zm17.5 0H70v2H47.5zM30 49h40v2H30zm0 5h17.5v2H30zm20 0h20v2H50zm-20 5h40v2H30zm0 5h7.5v2H30zm10 0h30v2H40zm-10 5h40v2H30zm0 5h40v2H30z"/></svg>

After

Width:  |  Height:  |  Size: 390 B

BIN
app/assets/images/admin/events.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

1
app/assets/images/admin/events.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 640"><path d="M510 209.6c0-68.5-47.8-124.2-106.6-124.2-16 0-31.8 4.3-46.3 12.5-19-42-57-70-101-70-43 0-81 28-101 70-14-9-30-13-46-13C50 85 2 141 2 209c0 59 36.8 123.2 88.4 136L65 380.4h35.6l-7.6 15c-8.2 16.4-3 36.4 12.3 46.5 5 3 8.2 8 8.8 14 1 6-1 12-5 16l11 12c8-8 12-19 11-30s-7-21-16-27c-8-5.6-11-16.5-7-25.5l11-22.4h27l-24-34c30-5 57.6-28 75.5-62.7 13 10.5 27.6 18.2 43.5 21.3L216 338h35l-7.6 15c-8.2 16.5-3 36.5 12.3 46.6 5 3.2 8.2 8.5 8.8 14.5.6 6-1.5 12-5.7 16l-8.5 9 11.7 11 8-8.5c7.8-8 11.6-18.5 10.6-29.3-1.2-11-7-20.5-16-26.5-8.4-5.5-11.3-16.4-7-25.4l11.4-22h27.5l-25-34c16-3 30.6-11 43.5-21.5 17.3 33.7 43.8 56 72.6 62.2l-25 34.5h35.7l-7.6 15c-8.3 16.5-3 36.5 12.2 46.6 5 3 8 8.5 8 14.5s-2 12-6 16l12 12c7-7.8 11-18.5 10-29-1-11-7-21-16-27-8.6-5.3-11-16.2-7-25.2l11-22.8h28l-24-33c53-11 91-76.6 91-136zM105.5 352l8.5 12H97l8.5-12zm3-21c-51.5 0-90-64-90-121.4 0-59.5 40.4-108 90-108 14 0 27.8 4 40.3 11.6-5 15-7.5 30.7-7.5 46.8 0 41 16.4 83.2 43 112-17.3 36.5-46 59-75.7 59zM256 311l8.5 12h-17l8.5-12zm0-21c-56.3 0-98.3-68.6-98.3-130 0-63.8 44-115.7 98.3-115.7s98.3 52 98.3 115.6c0 61-42 130-98.3 130zm139 74l8.5-12 8.5 12h-17zm8.4-33c-29.7 0-58.4-22.4-75.8-59 26.7-28.8 43-71 43-112 0-16-2.4-31.8-7.4-46.8 12.5-7.5 26.3-11.4 40.2-11.4 49.7 0 90.2 48.4 90.2 108 0 57-38.6 121.3-90.2 121.3z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/assets/images/admin/housing.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

1
app/assets/images/admin/housing.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path d="M67.5 20c0-5.5-4.5-10-10-10h-15c-5.5 0-10 4.5-10 10v2.5H5V90h90V22.5H67.5V20zm-30 0c0-2.8 2.2-5 5-5h15c2.8 0 5 2.2 5 5v2.5h-25V20zm36.3 7.5V85H26.3V27.5h47.5zm-63.8 0h13.8V85H10V27.5zM90 85H76.3V27.5H90V85z"/></svg>

After

Width:  |  Height:  |  Size: 286 B

BIN
app/assets/images/admin/locations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1
app/assets/images/admin/locations.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 56.25"><path d="M11 37.5l.8.4V17l-.7-.5M22 13v21l.6-.3h.4V13l-.3-.3M34.2 16l-1 .6V38l1-.7"/><path fill="none" d="M25 13l-2.5-1-10.7 4.3-7.4-4v22.2l7.5 4 10-4.2 2.5 1 8 3.3 7.4-4V12.2l-7.4 4-2.4-1"/><path d="M33 14l-1.8-.6-.7 2 2.6 1 8-4v22l-8 4.3-8-3.3-2.3-1h-.2L12 38.6l-7.6-4V12.2l7.4 4L22.5 12l2.6 1-1-2.6-1-.6L12 14 2.3 9v26.7l9.4 5 10.7-4.2L33 40.8l9.6-5v-27"/><path d="M28.2 3.4c-2.3 0-4 2-4 4.2v1.2l4 10 4-10.3c.2-.3.2-.6.2-1 0-2.2-2-4-4.2-4zm0 6.2c-1 0-1.7-.8-1.7-1.8S27.3 6 28.2 6s1.8.8 1.8 1.8-.8 1.8-1.8 1.8z"/></svg>

After

Width:  |  Height:  |  Size: 584 B

BIN
app/assets/images/admin/meals.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

1
app/assets/images/admin/meals.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" class="stroked"><circle cx="386.5" cy="16.5" r="3.6"/><path stroke-width="2" d="M392 16.5c0 2.4-3.5 7.2-4.9 9.1-.3.4-.9.4-1.2 0-1.4-2-4.9-6.7-4.9-9.1 0-3 2.5-5.5 5.5-5.5s5.5 2.4 5.5 5.5z"/><circle cx="404.1" cy="45.6" r="3.6"/><path stroke-width="2" d="M409.6 45.6c0 2.4-3.5 7.2-4.9 9.1-.3.4-.9.4-1.2 0-1.4-2-4.9-6.7-4.9-9.1 0-3 2.5-5.5 5.5-5.5 3.1.1 5.5 2.5 5.5 5.5z"/><path stroke-width="2" d="M381.2.9h27.9c4.5 0 8.1 3.7 8.1 8.1v54.6c0 4.5-3.7 8.1-8.1 8.1h-27.9c-4.5 0-8.1-3.7-8.1-8.1V9.1c0-4.5 3.6-8.2 8.1-8.2z"/><path d="M382 6.1h26.4c2.4 0 4.4 2 4.4 4.4v47.7c0 2.4-2 4.4-4.4 4.4H382c-2.4 0-4.4-2-4.4-4.4V10.5c-.1-2.4 1.9-4.4 4.4-4.4z"/><circle cx="395.2" cy="67.2" r="1.9"/><line x1="388.8" y1="3.6" x2="395.8" y2="3.6"/><line x1="398.7" y1="3.6" x2="402.2" y2="3.6"/><path stroke-width="2" d="M386.5 29.3h14.3c2 0 3.7 1.7 3.7 3.7s-1.7 3.7-3.7 3.7H386c-2.1 0-3.7 1.7-3.7 3.7v14.4c0 2.1 1.7 3.7 3.7 3.7h18.5"/><polygon stroke-width="2" points="23.7,80.7 78.4,80.7 24.7,27"/><polyline stroke-width="2" points="24.7,27 27.3,24.5 80.9,78.1 78.4,80.7"/><path stroke-width="0.9766" d="M30.5 22.5h.1c2.8 0 5.1 2.3 5.1 5.1v.2c0 2.8 2.3 5.1 5.1 5.1h.4c2.8 0 5.1 2.3 5.1 5.1v.1c0 2.8 2.3 5.1 5.1 5.1h.2c2.8 0 5.1 2.3 5.1 5.1v.3c0 2.8 2.3 5.1 5.1 5.1h.3c2.8 0 5.1 2.3 5.1 5.1v.3c0 2.8 2.3 5.1 5.1 5.1h.4c2.8 0 5.1 2.3 5.1 5.1v.3c0 2.8 2.3 5.1 5.1 5.1h.2"/><path d="M68.3 57.6v.2c0 2.8 2.3 5.1 5.1 5.1h.4M57.7 47.1v.2c0 2.8 2.3 5.1 5.1 5.1h.2M47.4 36.8c0 2.8 2.3 5.1 5.1 5.1h.1M42.1 31.6h-.2c-1.7 0-3.2-.8-4.1-2.1m-.9-3.2v.2c0 .5.1 1 .2 1.4"/><rect x="22.9" y="42.6" transform="rotate(-135 60.783 44.59)" stroke-width="2" width="75.9" height="3.9"/><line stroke-width="2" x1="32.5" y1="19.3" x2="32.5" y2="20.3"/><line stroke-width="2" x1="32.6" y1="25.3" x2="32.6" y2="29.4"/><line stroke-width="2" x1="86.2" y1="72.8" x2="83" y2="72.8"/><line stroke-width="2" x1="76.6" y1="72.8" x2="75.8" y2="72.8"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/assets/images/admin/payment.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1
app/assets/images/admin/payment.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 640"><path d="M92.1 227.3c-13.6 0-24.6 11-24.6 24.6 0 13.6 11 24.6 24.6 24.6s24.6-11 24.6-24.6c0-13.5-11-24.6-24.6-24.6zm0 32.8c-4.5 0-8.2-3.7-8.2-8.2 0-4.5 3.7-8.2 8.2-8.2 4.5 0 8.2 3.7 8.2 8.2 0 4.5-3.7 8.2-8.2 8.2z"/><path d="M359.9 133.8c1.7-6.9 2.6-14 2.6-21.2 0-49.7-40.4-90.1-90.1-90.1-49.7 0-90.1 40.4-90.1 90.1 0 5.9.6 11.7 1.7 17.3-7.3 1.7-14.6 3.5-21.5 5.6-16.7-24.4-44.6-39.3-74.3-39.3-26.1 0-52.1 13.5-52.1 13.5l20.5 7.7c20.7 7.8 36.8 24.3 43.9 45-29.8 17.8-52.7 40.1-66.6 65H2V342h31.8c17.5 31.3 49.5 58.6 91.1 77.7v69.8h98.3v-43.3c25 2.8 49.1 3.1 73.7.9v42.4h98.3v-66.1c72-30.1 114.8-81.6 114.8-138.7 0-66.8-58.7-125.3-150.1-150.9zm-87.5-94.9c40.7 0 73.7 33.1 73.7 73.7 0 18.3-6.6 35.7-18.8 49.2h-46.7v-9.7c9.5-3.4 16.4-12.4 16.4-23.1 0-13.6-11-24.6-24.6-24.6-4.5 0-8.2-3.7-8.2-8.2 0-4.5 3.7-8.2 8.2-8.2 4.5 0 8.2 3.7 8.2 8.2H297c0-10.7-6.9-19.7-16.4-23.1v-9.7h-16.4v9.7c-9.5 3.4-16.4 12.4-16.4 23.1 0 13.6 11 24.6 24.6 24.6 4.5 0 8.2 3.7 8.2 8.2 0 4.5-3.7 8.2-8.2 8.2-4.5 0-8.2-3.7-8.2-8.2h-16.4c0 10.7 6.9 19.7 16.4 23.1v9.7h-46.8c-12.1-13.5-18.8-30.8-18.8-49.2 0-40.7 33.1-73.7 73.8-73.7zm111.7 371.4l-5.2 2.1v60.8h-65.5v-44.3l-9.1 1c-29.3 3.3-58.1 3.1-88.1-1.1l-9.3-1.3v45.6h-65.5V409l-4.9-2.1c-42.5-18.5-74.6-45.7-90.3-76.7l-2.3-4.5H18.4v-81.9h25.4s19-45.2 70.3-70.3l5.5-3.1-1.5-6.1c-5.3-21-18-39.2-35.4-51.4 27.8-2 55 12.3 69.1 36.5l3.3 5.7s24.1-7.2 33.5-9.4c2.2 5.6 5 11 8.3 16.1h-14.6v16.4h180.3v-16.4H348c2.6-4 4.8-8.1 6.7-12.4 83.4 23.2 139 76.9 139 135.4-.1 51.3-41 98.3-109.6 125.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

1
app/assets/images/admin/payment_message.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 60"><path d="M8.5 46.7V35.3h-8v-34h47v34H19.9L8.5 46.7zm-6-13.4h8v8.6l8.6-8.6h26.4v-30h-43v30z"/><path d="M23.5 28.6v-2c-1-.1-1.8-.4-2.5-.7-.6-.3-1.2-.9-1.7-1.6-.5-.7-.7-1.6-.8-2.7l2-.4c.2 1.1.4 1.9.8 2.4.6.7 1.3 1.1 2.1 1.2v-6.5c-.8-.2-1.7-.5-2.6-1-.6-.4-1.1-.9-1.5-1.5-.4-.6-.5-1.4-.5-2.2 0-1.4.5-2.6 1.5-3.5.7-.6 1.7-1 3.1-1.1V8h1.2v1c1.2.1 2.1.5 2.8 1 .9.7 1.4 1.8 1.6 3l-2 .4c-.1-.8-.4-1.4-.8-1.8-.4-.4-.9-.7-1.6-.8v5.9l2 .6c.6.3 1.2.6 1.6 1 .4.4.7.9.9 1.4.2.6.3 1.1.3 1.8 0 1.4-.4 2.6-1.3 3.5-.9.9-2.1 1.4-3.5 1.5v2.1h-1.1zm0-17.9c-.8.1-1.4.4-1.9 1-.5.5-.7 1.1-.7 1.8s.2 1.3.6 1.7c.4.5 1 .8 2 1.1v-5.6zm1.2 14.1c.8-.1 1.4-.4 2-1 .5-.6.8-1.3.8-2.2 0-.7-.2-1.3-.5-1.8-.4-.4-1.1-.9-2.2-1.2v6.2z"/></svg>

After

Width:  |  Height:  |  Size: 762 B

1
app/assets/images/admin/paypal.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 640"><path d="M92.1 227.3c-13.6 0-24.6 11-24.6 24.6 0 13.6 11 24.6 24.6 24.6s24.6-11 24.6-24.6c0-13.5-11-24.6-24.6-24.6zm0 32.8c-4.5 0-8.2-3.7-8.2-8.2 0-4.5 3.7-8.2 8.2-8.2 4.5 0 8.2 3.7 8.2 8.2 0 4.5-3.7 8.2-8.2 8.2z"/><path d="M359.9 133.8c1.7-6.9 2.6-14 2.6-21.2 0-49.7-40.4-90.1-90.1-90.1-49.7 0-90.1 40.4-90.1 90.1 0 5.9.6 11.7 1.7 17.3-7.3 1.7-14.6 3.5-21.5 5.6-16.7-24.4-44.6-39.3-74.3-39.3-26.1 0-52.1 13.5-52.1 13.5l20.5 7.7c20.7 7.8 36.8 24.3 43.9 45-29.8 17.8-52.7 40.1-66.6 65H2V342h31.8c17.5 31.3 49.5 58.6 91.1 77.7v69.8h98.3v-43.3c25 2.8 49.1 3.1 73.7.9v42.4h98.3v-66.1c72-30.1 114.8-81.6 114.8-138.7 0-66.8-58.7-125.3-150.1-150.9zm-87.5-94.9c40.7 0 73.7 33.1 73.7 73.7 0 18.3-6.6 35.7-18.8 49.2h-46.7v-9.7c9.5-3.4 16.4-12.4 16.4-23.1 0-13.6-11-24.6-24.6-24.6-4.5 0-8.2-3.7-8.2-8.2 0-4.5 3.7-8.2 8.2-8.2 4.5 0 8.2 3.7 8.2 8.2H297c0-10.7-6.9-19.7-16.4-23.1v-9.7h-16.4v9.7c-9.5 3.4-16.4 12.4-16.4 23.1 0 13.6 11 24.6 24.6 24.6 4.5 0 8.2 3.7 8.2 8.2 0 4.5-3.7 8.2-8.2 8.2-4.5 0-8.2-3.7-8.2-8.2h-16.4c0 10.7 6.9 19.7 16.4 23.1v9.7h-46.8c-12.1-13.5-18.8-30.8-18.8-49.2 0-40.7 33.1-73.7 73.8-73.7zm111.7 371.4l-5.2 2.1v60.8h-65.5v-44.3l-9.1 1c-29.3 3.3-58.1 3.1-88.1-1.1l-9.3-1.3v45.6h-65.5V409l-4.9-2.1c-42.5-18.5-74.6-45.7-90.3-76.7l-2.3-4.5H18.4v-81.9h25.4s19-45.2 70.3-70.3l5.5-3.1-1.5-6.1c-5.3-21-18-39.2-35.4-51.4 27.8-2 55 12.3 69.1 36.5l3.3 5.7s24.1-7.2 33.5-9.4c2.2 5.6 5 11 8.3 16.1h-14.6v16.4h180.3v-16.4H348c2.6-4 4.8-8.1 6.7-12.4 83.4 23.2 139 76.9 139 135.4-.1 51.3-41 98.3-109.6 125.5z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/assets/images/admin/poster.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

1
app/assets/images/admin/poster.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 640"><path d="M233.8 277.6l-25.8-43-64 106.7h224L282.7 192l-49 85.6zm-52 42.4l26.2-44 13.6 22.8-12 21.2h-28zm52.3 0l48.8-85 48.5 85h-97z"/><path d="M416 85.3h-21.3V64h-21.4V0H352v64h-21.3v21.3H181.3V64H160V0h-21.3v64h-21.4v21.3H74.7V512h362.6V85.3H416zm-64 0h21.3v21.4H352V85.3zm-213.3 0H160v21.4h-21.3V85.3zM416 490.7H96v-384h21.3V128h64v-21.3h149.4V128h64v-21.3H416v384z"/><path d="M298.7 426.7h-85.4c-6 0-10.6 4.7-10.6 10.6s4.7 10.7 10.6 10.7h85.4c6 0 10.6-4.8 10.6-10.7s-4.7-10.6-10.6-10.6zm42.6-42.7H170.7c-6 0-10.7 4.8-10.7 10.7 0 6 4.8 10.6 10.7 10.6h170.6c6 0 10.7-4.7 10.7-10.6 0-6-4.8-10.7-10.7-10.7z"/></svg>

After

Width:  |  Height:  |  Size: 676 B

BIN
app/assets/images/admin/providers.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

1
app/assets/images/admin/providers.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 80"><path d="M2.2 46.5V64h23V46.5L14 38.3 2.2 46.5zm21 15.5h-19V47.5l9.6-6.8 9.5 6.8V62z"/><path d="M0 42.4v3.3l13.8-10 13.7 10v-3.3l-13.7-9.8m25 14V64h23V46.5L50 38.3l-11.5 8.2zm21 15.4h-19V47.5l9.4-6.8 9.6 6.8V62z"/><path d="M36.5 42.4v3.3l13.7-10 13.8 10v-3.3l-13.8-9.8M20.4 14v17.4h23.2V14L32 5.6 20.4 14zm21.2 15.4H22.4V15L32 8l9.6 7v14.4z"/><path d="M45.8 10L32 0 18.2 10v3L32 3.4 45.8 13"/></svg>

After

Width:  |  Height:  |  Size: 459 B

1
app/assets/images/admin/publish_schedule.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path d="M71.8 33.2c7.2 0 13-5.8 13-13s-5.8-13-13-13-13 5.8-13 13c0 1.5.3 2.9.7 4.2L36.9 41c-2.3-2.3-5.6-3.7-9.1-3.7-7.2 0-13 5.8-13 13s5.8 13 13 13c3.5 0 6.8-1.4 9.1-3.7l22.6 16.6c-.4 1.3-.7 2.7-.7 4.2 0 7.2 5.8 13 13 13s13-5.8 13-13-5.8-13-13-13c-3.5 0-6.8 1.4-9.1 3.7L40.1 54.4c.4-1.3.7-2.7.7-4.2s-.3-2.9-.7-4.2l22.6-16.6c2.3 2.4 5.5 3.8 9.1 3.8zm0-20c3.9 0 7 3.1 7 7s-3.1 7-7 7-7-3.1-7-7 3.1-7 7-7zm-44 44c-3.9 0-7-3.1-7-7s3.1-7 7-7 7 3.1 7 7-3.2 7-7 7zm44 16c3.9 0 7 3.1 7 7s-3.1 7-7 7-7-3.1-7-7 3.1-7 7-7z"/></svg>

After

Width:  |  Height:  |  Size: 582 B

1
app/assets/images/admin/registration_status.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><path d="M38.7 72.4l34.9-22.6-34.9-22.6v45.2zm4-37.8l23.5 15.2L42.7 65V34.6z"/><path d="M50 0C22.4 0 0 22.4 0 50s22.4 50 50 50 50-22.4 50-50S77.6 0 50 0zm0 96C24.6 96 4 75.4 4 50S24.6 4 50 4s46 20.6 46 46-20.6 46-46 46z"/></svg>

After

Width:  |  Height:  |  Size: 290 B

BIN
app/assets/images/admin/registrations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

1
app/assets/images/admin/registrations.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 26.25"><path d="M0 21h24V0H0v21zM19 1h4v3h-4V1zm0 4h4v3h-4V5zm0 4h4v3h-4V9zm0 4h4v3h-4v-3zm0 4h4v3h-4v-3zM14 1h4v3h-4V1zm0 4h4v3h-4V5zm0 4h4v3h-4V9zm0 4h4v3h-4v-3zm0 4h4v3h-4v-3zM9 1h4v3H9V1zm0 4h4v3H9V5zm0 4h4v3H9V9zm0 4h4v3H9v-3zm0 4h4v3H9v-3zM1 1h7v3H1V1zm0 4h7v3H1V5zm0 4h7v3H1V9zm0 4h7v3H1v-3zm0 4h7v3H1v-3z"/></svg>

After

Width:  |  Height:  |  Size: 377 B

BIN
app/assets/images/admin/schedule.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

1
app/assets/images/admin/schedule.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 73 67.5" class="stroked"><path stroke-width="2.5" d="M32.2 8v5.8H41v-6z"/><path d="M37.2 13.7v10m0 6.3v10m0 5.6v6.2h34v-50h-34v6m-1 6v9.8m0 6v10m0 6.4v5.8h-34v-50h34v6" stroke-width="3.5"/><path stroke-width="2.5" d="M32.2 24v5.8H41v-6zm0 16v5.8H41v-6zM8.5 13.8h18m-18 6.7h18m-18 6.3h18m-18 6.4h18m-18 6.6h18m20-26h18m-18 6.7h18m-18 6.3h18m-18 6.4h18m-18 6.6h18"/></svg>

After

Width:  |  Height:  |  Size: 423 B

BIN
app/assets/images/admin/stats.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

1
app/assets/images/admin/stats.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 112.5"><path d="M74.8 80V41.8H61.6V80H58V26.8H45V80h-3.2V42H28.6v38h-3V57.6H12.3V80h-3V10h-4v74.2H86V80H74.8zm-9-34h4.7v33.5H66V46zM49.4 31H54v48.7h-4.7V31zM33 46.3h4.5v33.5H33V46.3zM16.5 80V61.8H21V80h-4.5z"/></svg>

After

Width:  |  Height:  |  Size: 272 B

1
app/assets/images/admin/suggested_amounts.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 125"><switch><foreignObject requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/" x="0" y="0" width="1" height="1"/><g><g fill="none" stroke="#000" stroke-width="3" stroke-miterlimit="10"><line x1="19.3" y1="50" x2="19.3" y2="57.1"/><line x1="36.8" y1="50" x2="36.8" y2="57.1"/><line x1="19.3" y1="56" x2="19.3" y2="63.1"/><line x1="36.8" y1="56" x2="36.8" y2="63.1"/><line x1="19.3" y1="62" x2="19.3" y2="69.1"/><line x1="36.8" y1="62" x2="36.8" y2="69.1"/><ellipse cx="28" cy="50" rx="8.8" ry="4.9"/><path d="M36.8 56c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="19.3" y1="68" x2="19.3" y2="75.1"/><line x1="36.8" y1="68" x2="36.8" y2="75.1"/><line x1="41.3" y1="38" x2="41.3" y2="45.1"/><line x1="58.8" y1="38" x2="58.8" y2="45.1"/><line x1="41.3" y1="44" x2="41.3" y2="51.1"/><line x1="58.8" y1="44" x2="58.8" y2="51.1"/><line x1="41.3" y1="50" x2="41.3" y2="57.1"/><line x1="58.8" y1="50" x2="58.8" y2="57.1"/><line x1="41.3" y1="56" x2="41.3" y2="63.1"/><line x1="58.8" y1="56" x2="58.8" y2="63.1"/><line x1="41.3" y1="62" x2="41.3" y2="69.1"/><line x1="58.8" y1="62" x2="58.8" y2="69.1"/><ellipse cx="50" cy="38" rx="8.8" ry="4.9"/><path d="M58.8 44c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5m17.6 6c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="41.3" y1="68" x2="41.3" y2="75.1"/><line x1="58.8" y1="68" x2="58.8" y2="75.1"/><line x1="63.3" y1="26" x2="63.3" y2="33.1"/><line x1="63.3" y1="32" x2="63.3" y2="39.1"/><line x1="63.3" y1="38" x2="63.3" y2="45.1"/><line x1="63.3" y1="44" x2="63.3" y2="51.1"/><line x1="63.3" y1="50" x2="63.3" y2="57.1"/><line x1="63.3" y1="56" x2="63.3" y2="63.1"/><line x1="63.3" y1="61.1" x2="63.3" y2="68.2"/><line x1="63.3" y1="67" x2="63.3" y2="74.1"/><ellipse cx="72" cy="26" rx="8.8" ry="4.9"/><path d="M80.8 32c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="26" x2="80.8" y2="33.1"/><path d="M80.8 38c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="32" x2="80.8" y2="39.1"/><path d="M80.8 44c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="38" x2="80.8" y2="45.1"/><path d="M80.8 50c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="44" x2="80.8" y2="51.1"/><path d="M80.8 56c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="50" x2="80.8" y2="57.1"/><path d="M80.8 62c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="56" x2="80.8" y2="63.1"/><path d="M80.8 68c0 2.8-4 5-8.8 5s-8.8-2.2-8.8-5"/><line x1="80.8" y1="61.1" x2="80.8" y2="68.2"/><path d="M80.8 74c0 2.7-4 5-8.8 5s-8.8-2.3-8.8-5"/><line x1="80.8" y1="67" x2="80.8" y2="74.1"/></g></g></switch></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/assets/images/admin/workshop_times.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

1
app/assets/images/admin/workshop_times.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 91 113.75"><path d="M45.2 18.6C30 18.6 17.6 31 17.6 46.2 17.6 61.5 30 74 45.2 74c15.2 0 27.6-12.6 27.6-28 0-15.2-12.4-27.6-27.6-27.6zm0 52C31.8 70.6 21 59.6 21 46c0-13 10.8-24 24.2-24 13.4 0 24.2 11 24.2 24.2 0 13.4-10.8 24.3-24.2 24.3z"/><path d="M47 26.3h-3.4V48h11v-3.5H47m-3.4 17.2H47V66h-3.4zM25.2 44.5h4.4V48h-4.4zm35.6 0h4.4V48h-4.4zm-29.2-13l3.2 3-2.3 2.4-3.2-3zM58.8 61l-3.2-3 2.3-2.6 3 3zM33 62l-2.5-2 3-3.3L36 59zm24.4-31.7l2.5 2.3-3 3.2-2.8-2.3z"/></svg>

After

Width:  |  Height:  |  Size: 519 B

BIN
app/assets/images/conferences.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

0
app/assets/images/bb-icon-fb.png → app/assets/images/facebook.png

Before

Width:  |  Height:  |  Size: 308 B

After

Width:  |  Height:  |  Size: 308 B

1
app/assets/images/facebook.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-723 0 1000 1000" class="icons"><path d="M222.5,0.5h-891.1c-29.9,0-54,24.1-54,54v891.1c0,29.9,24.1,54,54,54h479.5V612.3h-130.5V461.7h130.5V346.8 c0-120.4,74.7-195.3,192.2-195.3c70.8,0,118.4,5.5,118.4,5.5v135.8H41.9c-50.5,0-74.3,17.8-74.3,71.4v97.5h148.8L97.2,612.3H-32.4 v387.2h255c29.9,0,54-24.1,54-54V54.5C276.5,24.6,252.4,0.5,222.5,0.5z"/></svg>

After

Width:  |  Height:  |  Size: 397 B

0
app/assets/images/bb-icon-github.png → app/assets/images/github.png

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 470 B

1
app/assets/images/github.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="icons"><path xmlns="http://www.w3.org/2000/svg" d="M512 0C229.25 0 0 229.2 0 512c0 226.2 146.7 418.1 350.2 485.8 25.6 4.7 34.938-11.125 34.938-24.625 0-12.188-0.469-52.562-0.719-95.312C242 908.8 211.9 817.5 211.9 817.5c-23.312-59.125-56.844-74.875-56.844-74.875-46.531-31.75 3.53-31.125 3.53-31.125 51.4 3.6 78.5 52.8 78.5 52.8 45.7 78.2 119.9 55.6 149 42.5 4.654-33 17.904-55.625 32.5-68.375C304.906 725.4 185.3 681.5 185.3 485.312c0-55.938 19.969-101.562 52.656-137.406-5.219-13-22.844-65.094 5.062-135.562 0 0 42.938-13.75 140.8 52.5 40.812-11.406 84.594-17.031 128.125-17.219 43.5 0.2 87.3 5.9 128.2 17.3 97.688-66.312 140.688-52.5 140.688-52.5 28 70.5 10.4 122.6 5.1 135.5 32.8 35.8 52.6 81.5 52.6 137.4 0 196.688-119.75 240-233.812 252.7 18.4 15.9 34.8 47 34.8 94.8 0 68.438-0.688 123.625-0.688 140.5 0 13.6 9.3 29.6 35.2 24.562C877.438 930 1024 738.1 1024 512 1024 229.2 794.8 0 512 0z"/></svg>

After

Width:  |  Height:  |  Size: 972 B

2
app/assets/images/logo-text.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

2
app/assets/images/logo.svg

@ -1,2 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 291 288.5" id="bb-icon-logo"><path d="m290.7 136.1c-8.8.9-16.9-5.1-18.4-14-1.5-8.8 4-17.3 12.6-19.4-1.6-5.4-3.5-10.7-5.7-15.8-8 3.9-17.6 1-22.1-6.8-4.5-7.8-2.1-17.6 5.2-22.5-3.3-4.5-7-8.8-10.8-12.9-6.2 6.3-16.2 6.9-23.1 1.2-6.9-5.8-8-15.8-2.8-23-4.7-3.1-9.5-5.9-14.5-8.4-3.6 8.1-12.9 12.1-21.3 9-8.4-3.1-12.9-12.1-10.5-20.6-5.4-1.3-10.9-2.2-16.5-2.9-.6 8.8-8 15.8-16.9 15.8-9 0-16.3-7-16.9-15.8-5.5.6-10.9 1.6-16.2 2.8 2.4 8.5-2.1 17.5-10.6 20.6-8.4 3-17.7-1-21.3-9.1-5 2.5-9.9 5.3-14.5 8.4 5.2 7.2 4 17.2-2.9 23-6.9 5.7-17 5.1-23.1-1.2-3.8 4.1-7.5 8.3-10.8 12.8 7.3 5 9.6 14.8 5.1 22.6-4.5 7.8-14.2 10.6-22.1 6.7-2.2 5.1-4.1 10.4-5.8 15.8 8.6 2.2 14.1 10.6 12.6 19.4-1.6 8.8-9.7 14.8-18.5 13.9-.2 2.8-.3 5.7-.3 8.6 0 2.8.1 5.5.2 8.2 8.8-.9 16.9 5.1 18.4 14 1.5 8.8-4 17.3-12.6 19.4 1.6 5.4 3.5 10.7 5.7 15.8 8-3.9 17.6-1 22.1 6.8 4.5 7.8 2.1 17.6-5.2 22.5 3.3 4.5 7 8.8 10.8 12.9 6.2-6.3 16.2-6.9 23.1-1.2 6.9 5.8 8 15.8 2.8 23 4.7 3.1 9.5 5.9 14.5 8.4 3.6-8.1 12.9-12.1 21.3-9 8.4 3.1 12.9 12.1 10.5 20.6 5.4 1.3 10.9 2.2 16.5 2.9.6-8.8 8-15.8 16.9-15.8 9 0 16.3 7 16.9 15.8 5.5-.6 10.9-1.6 16.1-2.8-2.4-8.5 2.1-17.5 10.6-20.6 8.4-3 17.7 1 21.3 9.1 5-2.5 9.9-5.3 14.6-8.4-5.2-7.2-4-17.2 2.9-23 6.9-5.7 17-5.1 23.1 1.2 3.8-4.1 7.5-8.3 10.8-12.8-7.3-5-9.6-14.8-5.1-22.6 4.5-7.8 14.2-10.6 22.2-6.7 2.2-5.1 4.1-10.4 5.8-15.8-8.6-2.2-14.1-10.6-12.6-19.4 1.6-8.8 9.7-14.8 18.5-13.9.2-2.8.3-5.7.3-8.6-.1-2.8-.1-5.5-.3-8.2m-117.5 55.4c-.6 1.2-1.2 2.4-1.8 3.5-.6 1.1-1.2 2.1-1.9 3.1-4.5 5.8-10.2 10-17 12.6-2.6 1-5.4 1.7-8.2 2.1-2.8.4-5.8.7-8.9.9-1.6.1-3.2.1-4.8-.1-1.6-.2-3.2-.4-4.7-.5-.7 0-1.3-.1-1.9-.3-.6-.2-1.2-.3-1.9-.3-.6 0-1.1-.2-1.7-.4-.6-.3-1.2-.4-1.9-.3-.6 0-1.1-.1-1.7-.3-.6-.2-1.2-.4-1.8-.6l-57-15.5c-2.2-.6-4-1.2-5.5-1.8-1.4-.6-2.3-1.8-2.5-3.5-.1-1.1.2-2.8.8-4.9.6-2.1 1.2-3.9 1.5-5.4l30.8-114.8c.4-1.6.8-3.2 1.2-5 .4-1.8 1.1-3.1 2-4 .8-.8 1.9-1.2 3.5-1.2.3-.1.6 0 .8.1.2.1.5.2.8.1l58.3 15.6c.9.2 1.8.5 2.8.6.9.2 1.8.4 2.5.8.6.4 1.2.7 1.9.7.7 0 1.3.2 2 .5l1.2.3c.7.5 1.5.8 2.4.9.9.2 1.7.5 2.6 1 1 .5 1.9 1 2.9 1.4.9.4 1.9.9 2.9 1.4 2.2 1.6 4.3 3.1 6.3 4.5 2 1.4 3.7 3.1 5.2 4.8 2.1 2.5 3.7 5.4 4.6 8.6 1 3.2 1.5 6.7 1.6 10.5 0 1-.1 1.9-.2 2.9-.2.9-.3 2-.3 3.1 0 .6-.1 1.1-.3 1.6-.2.5-.3 1-.3 1.6 0 .4-.1.9-.3 1.5-.2.6-.4 1-.6 1.2l-.5 1.8c-.1.4-.3.8-.5 1.3-.2.5-.3.9-.4 1.1-.5.8-.9 1.6-1.1 2.3-.3.7-.6 1.3-1 1.9-3 4.2-6.2 7.5-9.7 9.8-1.2.7-2.3 1.2-3.6 1.6-1.2.4-2.4 1-3.4 1.8-.3.2-.7.5-1.2.8-.5.4-.6.9-.5 1.6 0 1.1.6 2.2 1.8 3.3 1.2 1.1 2.3 2.1 3.2 3 2.9 3.3 5 6.8 6.4 10.5 1.3 3.6 2 7.5 2.1 11.9.1 1.2.1 2.3-.1 3.4-.2 1.1-.3 2.3-.3 3.4l-.6 2.2c-.1 1.5-.6 3.4-1.4 5.7-1.2 2.6-1.9 4.3-2.6 5.6m38.9 17.5c-.2 1.2-.5 2.5-.9 4l-3.8 14.1c-.4 1.4-.8 2.7-1.2 3.9-.4 1.1-1.1 1.9-1.9 2.4-1.1.4-2.3.5-3.6.2-1.3-.3-2.7-.6-4.1-1l-13.1-3.5c-1.4-.4-2.8-.8-4.1-1.2-1.3-.4-2.2-1.1-2.6-2.1-.4-1-.6-2.1-.4-3.3.2-1.3.5-2.6.9-4.1l3.3-12.3c.3-1.3.7-2.6 1-3.8.3-1.2.9-2.2 1.6-2.8.7-.6 1.9-1 3.5-1.2.3-.1.6 0 .9.1.3.2.6.2.9.1l15.4 4.1c1.6.4 3 .8 4.4 1.3 1.4.4 2.4 1.1 3.1 2 .7.9.9 1.9.7 3.1m28.4-108.9c-.3 1.2-.6 2.4-1 3.7l-5.8 21.7c-.2.8-.4 1.7-.5 2.7-.1 1-.4 1.8-.9 2.4l-.6 2.2c-.5.8-.9 1.8-1.1 2.8-.2 1-.5 1.8-1 2.6-.4.6-.7 1.2-.8 1.8-.1.6-.4 1.2-.8 1.8-.6 1.1-1 2.2-1.3 3.3-.3 1.1-.7 2.2-1.3 3.1-.3.5-.5 1-.6 1.4-.1.5-.3.9-.6 1.4-.7 1.6-1.4 3.3-2 5.1-.6 1.8-1.4 3.5-2.2 5.1-.5.8-.8 1.7-1 2.5-.1.8-.5 1.7-1 2.7-1.2 2.2-2.1 4.6-2.8 7.1-.7 2.5-1.8 4.9-3 7-.9 1.7-1.6 3.5-2.2 5.4-.6 1.9-1.6 3.1-3.2 3.7-.5.2-1 .2-1.5.2-.6 0-1.2 0-1.9-.1l-2.7-.7c-1.3-.3-2.4-.8-3.3-1.3-.9-.5-1.5-1.2-1.9-2-.4-1-.5-1.9-.3-2.8.2-.9.4-1.9.4-3 0-1.5.2-3.1.5-4.7.4-1.6.5-3.1.5-4.7.3-1 .4-1.8.4-2.2.1-.8.2-1.6.4-2.4.2-.8.4-1.6.4-2.4 0-2 .2-4 .7-6 .5-2 .8-4 .9-6 0-.7.1-1.3.3-1.9.2-.6.3-1.2.3-1.9.1-1.2.2-2.5.5-3.8.3-1.3.5-2.7.6-4 .1-.3.1-.5.1-.8 0-.3 0-.5.1-.8 0-1.1.2-2.2.4-3.1.3-1 .4-2 .4-3.1.1-3 .7-6.2 1.6-9.6 1-3.4 1.9-6.8 2.8-10.1l4-15.1c.4-1.4.8-2.8 1.1-4.1.3-1.3 1-2.3 1.9-3.1.9-.6 1.9-.9 3.2-.8.3-.1.6 0 .8.1.2.1.5.2.8.1l15.1 4c1.6.4 3 .9 4.3 1.4 1.3.5 2.2 1.3 2.6 2.4.5.6.5 1.6.2 2.8"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 291 288.5" id="bb-icon-logo" class="icons bb-icon-logo"><path d="m290.7 136.1c-8.8.9-16.9-5.1-18.4-14-1.5-8.8 4-17.3 12.6-19.4-1.6-5.4-3.5-10.7-5.7-15.8-8 3.9-17.6 1-22.1-6.8-4.5-7.8-2.1-17.6 5.2-22.5-3.3-4.5-7-8.8-10.8-12.9-6.2 6.3-16.2 6.9-23.1 1.2-6.9-5.8-8-15.8-2.8-23-4.7-3.1-9.5-5.9-14.5-8.4-3.6 8.1-12.9 12.1-21.3 9-8.4-3.1-12.9-12.1-10.5-20.6-5.4-1.3-10.9-2.2-16.5-2.9-.6 8.8-8 15.8-16.9 15.8-9 0-16.3-7-16.9-15.8-5.5.6-10.9 1.6-16.2 2.8 2.4 8.5-2.1 17.5-10.6 20.6-8.4 3-17.7-1-21.3-9.1-5 2.5-9.9 5.3-14.5 8.4 5.2 7.2 4 17.2-2.9 23-6.9 5.7-17 5.1-23.1-1.2-3.8 4.1-7.5 8.3-10.8 12.8 7.3 5 9.6 14.8 5.1 22.6-4.5 7.8-14.2 10.6-22.1 6.7-2.2 5.1-4.1 10.4-5.8 15.8 8.6 2.2 14.1 10.6 12.6 19.4-1.6 8.8-9.7 14.8-18.5 13.9-.2 2.8-.3 5.7-.3 8.6 0 2.8.1 5.5.2 8.2 8.8-.9 16.9 5.1 18.4 14 1.5 8.8-4 17.3-12.6 19.4 1.6 5.4 3.5 10.7 5.7 15.8 8-3.9 17.6-1 22.1 6.8 4.5 7.8 2.1 17.6-5.2 22.5 3.3 4.5 7 8.8 10.8 12.9 6.2-6.3 16.2-6.9 23.1-1.2 6.9 5.8 8 15.8 2.8 23 4.7 3.1 9.5 5.9 14.5 8.4 3.6-8.1 12.9-12.1 21.3-9 8.4 3.1 12.9 12.1 10.5 20.6 5.4 1.3 10.9 2.2 16.5 2.9.6-8.8 8-15.8 16.9-15.8 9 0 16.3 7 16.9 15.8 5.5-.6 10.9-1.6 16.1-2.8-2.4-8.5 2.1-17.5 10.6-20.6 8.4-3 17.7 1 21.3 9.1 5-2.5 9.9-5.3 14.6-8.4-5.2-7.2-4-17.2 2.9-23 6.9-5.7 17-5.1 23.1 1.2 3.8-4.1 7.5-8.3 10.8-12.8-7.3-5-9.6-14.8-5.1-22.6 4.5-7.8 14.2-10.6 22.2-6.7 2.2-5.1 4.1-10.4 5.8-15.8-8.6-2.2-14.1-10.6-12.6-19.4 1.6-8.8 9.7-14.8 18.5-13.9.2-2.8.3-5.7.3-8.6-.1-2.8-.1-5.5-.3-8.2m-117.5 55.4c-.6 1.2-1.2 2.4-1.8 3.5-.6 1.1-1.2 2.1-1.9 3.1-4.5 5.8-10.2 10-17 12.6-2.6 1-5.4 1.7-8.2 2.1-2.8.4-5.8.7-8.9.9-1.6.1-3.2.1-4.8-.1-1.6-.2-3.2-.4-4.7-.5-.7 0-1.3-.1-1.9-.3-.6-.2-1.2-.3-1.9-.3-.6 0-1.1-.2-1.7-.4-.6-.3-1.2-.4-1.9-.3-.6 0-1.1-.1-1.7-.3-.6-.2-1.2-.4-1.8-.6l-57-15.5c-2.2-.6-4-1.2-5.5-1.8-1.4-.6-2.3-1.8-2.5-3.5-.1-1.1.2-2.8.8-4.9.6-2.1 1.2-3.9 1.5-5.4l30.8-114.8c.4-1.6.8-3.2 1.2-5 .4-1.8 1.1-3.1 2-4 .8-.8 1.9-1.2 3.5-1.2.3-.1.6 0 .8.1.2.1.5.2.8.1l58.3 15.6c.9.2 1.8.5 2.8.6.9.2 1.8.4 2.5.8.6.4 1.2.7 1.9.7.7 0 1.3.2 2 .5l1.2.3c.7.5 1.5.8 2.4.9.9.2 1.7.5 2.6 1 1 .5 1.9 1 2.9 1.4.9.4 1.9.9 2.9 1.4 2.2 1.6 4.3 3.1 6.3 4.5 2 1.4 3.7 3.1 5.2 4.8 2.1 2.5 3.7 5.4 4.6 8.6 1 3.2 1.5 6.7 1.6 10.5 0 1-.1 1.9-.2 2.9-.2.9-.3 2-.3 3.1 0 .6-.1 1.1-.3 1.6-.2.5-.3 1-.3 1.6 0 .4-.1.9-.3 1.5-.2.6-.4 1-.6 1.2l-.5 1.8c-.1.4-.3.8-.5 1.3-.2.5-.3.9-.4 1.1-.5.8-.9 1.6-1.1 2.3-.3.7-.6 1.3-1 1.9-3 4.2-6.2 7.5-9.7 9.8-1.2.7-2.3 1.2-3.6 1.6-1.2.4-2.4 1-3.4 1.8-.3.2-.7.5-1.2.8-.5.4-.6.9-.5 1.6 0 1.1.6 2.2 1.8 3.3 1.2 1.1 2.3 2.1 3.2 3 2.9 3.3 5 6.8 6.4 10.5 1.3 3.6 2 7.5 2.1 11.9.1 1.2.1 2.3-.1 3.4-.2 1.1-.3 2.3-.3 3.4l-.6 2.2c-.1 1.5-.6 3.4-1.4 5.7-1.2 2.6-1.9 4.3-2.6 5.6m38.9 17.5c-.2 1.2-.5 2.5-.9 4l-3.8 14.1c-.4 1.4-.8 2.7-1.2 3.9-.4 1.1-1.1 1.9-1.9 2.4-1.1.4-2.3.5-3.6.2-1.3-.3-2.7-.6-4.1-1l-13.1-3.5c-1.4-.4-2.8-.8-4.1-1.2-1.3-.4-2.2-1.1-2.6-2.1-.4-1-.6-2.1-.4-3.3.2-1.3.5-2.6.9-4.1l3.3-12.3c.3-1.3.7-2.6 1-3.8.3-1.2.9-2.2 1.6-2.8.7-.6 1.9-1 3.5-1.2.3-.1.6 0 .9.1.3.2.6.2.9.1l15.4 4.1c1.6.4 3 .8 4.4 1.3 1.4.4 2.4 1.1 3.1 2 .7.9.9 1.9.7 3.1m28.4-108.9c-.3 1.2-.6 2.4-1 3.7l-5.8 21.7c-.2.8-.4 1.7-.5 2.7-.1 1-.4 1.8-.9 2.4l-.6 2.2c-.5.8-.9 1.8-1.1 2.8-.2 1-.5 1.8-1 2.6-.4.6-.7 1.2-.8 1.8-.1.6-.4 1.2-.8 1.8-.6 1.1-1 2.2-1.3 3.3-.3 1.1-.7 2.2-1.3 3.1-.3.5-.5 1-.6 1.4-.1.5-.3.9-.6 1.4-.7 1.6-1.4 3.3-2 5.1-.6 1.8-1.4 3.5-2.2 5.1-.5.8-.8 1.7-1 2.5-.1.8-.5 1.7-1 2.7-1.2 2.2-2.1 4.6-2.8 7.1-.7 2.5-1.8 4.9-3 7-.9 1.7-1.6 3.5-2.2 5.4-.6 1.9-1.6 3.1-3.2 3.7-.5.2-1 .2-1.5.2-.6 0-1.2 0-1.9-.1l-2.7-.7c-1.3-.3-2.4-.8-3.3-1.3-.9-.5-1.5-1.2-1.9-2-.4-1-.5-1.9-.3-2.8.2-.9.4-1.9.4-3 0-1.5.2-3.1.5-4.7.4-1.6.5-3.1.5-4.7.3-1 .4-1.8.4-2.2.1-.8.2-1.6.4-2.4.2-.8.4-1.6.4-2.4 0-2 .2-4 .7-6 .5-2 .8-4 .9-6 0-.7.1-1.3.3-1.9.2-.6.3-1.2.3-1.9.1-1.2.2-2.5.5-3.8.3-1.3.5-2.7.6-4 .1-.3.1-.5.1-.8 0-.3 0-.5.1-.8 0-1.1.2-2.2.4-3.1.3-1 .4-2 .4-3.1.1-3 .7-6.2 1.6-9.6 1-3.4 1.9-6.8 2.8-10.1l4-15.1c.4-1.4.8-2.8 1.1-4.1.3-1.3 1-2.3 1.9-3.1.9-.6 1.9-.9 3.2-.8.3-.1.6 0 .8.1.2.1.5.2.8.1l15.1 4c1.6.4 3 .9 4.3 1.4 1.3.5 2.2 1.3 2.6 2.4.5.6.5 1.6.2 2.8"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

3
app/assets/images/octicat.svg

@ -1,3 +0,0 @@
<svg height="1024" width="1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 0C229.25 0 0 229.25 0 512c0 226.25 146.688 418.125 350.156 485.812 25.594 4.688 34.938-11.125 34.938-24.625 0-12.188-0.469-52.562-0.719-95.312C242 908.812 211.906 817.5 211.906 817.5c-23.312-59.125-56.844-74.875-56.844-74.875-46.531-31.75 3.53-31.125 3.53-31.125 51.406 3.562 78.47 52.75 78.47 52.75 45.688 78.25 119.875 55.625 149 42.5 4.654-33 17.904-55.625 32.5-68.375C304.906 725.438 185.344 681.5 185.344 485.312c0-55.938 19.969-101.562 52.656-137.406-5.219-13-22.844-65.094 5.062-135.562 0 0 42.938-13.75 140.812 52.5 40.812-11.406 84.594-17.031 128.125-17.219 43.5 0.188 87.312 5.875 128.188 17.281 97.688-66.312 140.688-52.5 140.688-52.5 28 70.531 10.375 122.562 5.125 135.5 32.812 35.844 52.625 81.469 52.625 137.406 0 196.688-119.75 240-233.812 252.688 18.438 15.875 34.75 47 34.75 94.75 0 68.438-0.688 123.625-0.688 140.5 0 13.625 9.312 29.562 35.25 24.562C877.438 930 1024 738.125 1024 512 1024 229.25 794.75 0 512 0z" />
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

15
app/assets/javascripts/editor.js

@ -112,4 +112,19 @@
toggle();
checkbox.addEventListener('change', function(event) { toggle(); });
});
Array.prototype.forEach.call(document.querySelectorAll('fieldset.translator'), function(translator) {
Array.prototype.forEach.call(translator.querySelectorAll('.locale-select a'), function(selector) {
selector.addEventListener('click', function(event) {
event.preventDefault();
var locale = event.target.parentElement.getAttribute('data-locale');
Array.prototype.forEach.call(translator.querySelectorAll('.locale-select li'), function(_selector) {
_selector.className = _selector.getAttribute('data-locale') == locale ? 'selected' : '';
});
Array.prototype.forEach.call(translator.querySelectorAll('.text-editors li'), function(editor) {
editor.className = editor.getAttribute('data-locale') == locale ? 'selected' : '';
});
});
});
});
})();

31
app/assets/javascripts/filefield.js

@ -0,0 +1,31 @@
(function() {
document.addEventListener('DOMContentLoaded', function() {
var fields = document.getElementsByClassName('file-field');
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var input = field.getElementsByTagName('input')[0];
var image = field.getElementsByTagName('img')[0];
var state = field.getElementsByClassName('file-field-name')[0];
input.onchange = function() {
state.className = 'file-field-name selected';
state.innerHTML = this.value.split(/[\/\\]/).reverse()[0];
var uploadButton = this.form.querySelector('[value="upload"]');
if (uploadButton) {
uploadButton.setAttribute('data-enabled', '1');
}
if (this.files && this.files[0] && typeof FileReader !== "undefined") {
var reader = new FileReader();
reader.onload = function (e) {
image.className = 'changed';
image.src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
}
}
}
}, false);
})();

4
app/assets/javascripts/jquery.min.js

File diff suppressed because one or more lines are too long

11
app/assets/javascripts/main.js

@ -230,4 +230,15 @@
});
};
initNode();
document.addEventListener('DOMContentLoaded', function() {
var errors = document.getElementsByClassName('has-error');
if (errors.length <= 0) {
errors = document.getElementsByClassName('info-message');
}
if (errors.length > 0) {
errors[0].scrollIntoView();
}
});
})();

117
app/assets/javascripts/map.js

@ -0,0 +1,117 @@
(function() {
function loadMap() {
var projection = d3.geo.mercator();
var path = d3.geo.path().projection(projection);
var tooltip = document.getElementById('tooltip');
var initialScale = 3.5;
var initialPosition = [-100, -175];
var zoom = d3.behavior.zoom()
.scaleExtent([1, 20])
.scale(initialScale).translate(initialPosition)
.on("zoom", function() {
setZoom(d3.event.translate, d3.event.scale);
});
function setZoom(translate, scale) {
container.attr("transform", "translate(" + translate + ") scale(" + scale + ")").attr('data-scale', scale);
}
var container = d3.select('#map').call(zoom).insert('g', ':first-child').attr('class', 'map');
setZoom(initialPosition, initialScale);
container.append("path")
.datum(d3.geo.graticule())
.attr("class", "graticule")
.attr("d", path);
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
d3.json('/assets/world-110m.json', function(error, world) {
if (error) {
throw error;
}
container.selectAll('path')
.data(topojson.feature(world, world.objects.countries).features)
.enter()
.append('path')
.attr('d', path)
.attr('class', 'country');
var year = (new Date()).getFullYear();
var conferences = document.querySelectorAll('#conferences .conference');
var conference_path = []
for (var i = 0; i < conferences.length; i++) {
var d = conferences[i];
if (d.getAttribute('data-t') === 'annual') {
var coords = projection([d.getAttribute('data-o'), d.getAttribute('data-a')]);
if (conference_path.length) {
conference_path[conference_path.length - 1].x2 = coords[0];
conference_path[conference_path.length - 1].y2 = coords[1];
}
conference_path.push({
x1: coords[0],
y1: coords[1]
});
}
}
container.append('defs').html('<filter id="svg-gooey-filter"><feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blur"></feGaussianBlur><feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="svg-gooey-filter"></feColorMatrix><feComposite in="SourceGraphic" in2="svg-gooey-filter" operator="atop"></feComposite></filter>')
var regionalConferences = container.append('g').attr('filter', 'url(#svg-gooey-filter)').attr('class', 'cities regional-conferences');
var annualConferences = container.append('g').attr('filter', 'url(#svg-gooey-filter)').attr('class', 'cities annual-conferences');
function mouseover(e) {
c = document.getElementById('conference-' + event.target.getAttribute('data-c'));
tooltip.innerHTML = '<h3>' + c.querySelector('.title').innerHTML + '</h3>' +
'<div class="conference-details">' + c.querySelector('.conference-details').innerHTML + '</div>';
tooltip.className = 'open';
}
function mouseout(e) {
tooltip.className = '';
}
function click(e) {
l = document.querySelector('#conference-' + event.target.getAttribute('data-c') + ' .conference-link');
window.location.href = l.getAttribute('href');
}
for (var i = conferences.length - 1; i >= 0; i--) {
var c = conferences[i];
var type = c.getAttribute('data-t');
var coords = projection([c.getAttribute('data-o'), c.getAttribute('data-a')]);
(type === 'annual' ? annualConferences : regionalConferences)
.append('circle')
.attr('class', 'city type-' + type)
.attr('data-c', c.id.replace(/^conference\-/, ''))
.attr('cx', function(d) { return coords[0]; })
.attr('cy', function(d) { return coords[1]; })
.attr('r', Math.max(3,
(15 - (
(year - parseInt(c.getAttribute('data-y'))) * 2.5)) * 1.125)
)
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', click);
}
});
d3.select("#map").attr('class', 'loaded');
}
document.onreadystatechange = function () {
if (document.readyState == 'complete') {
loadMap();
}
};
})();

26
app/assets/javascripts/userfield.js

@ -0,0 +1,26 @@
(function() {
function find_user(email, f) {
var request = new XMLHttpRequest();
request.open('POST', '/user/find', true);
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
request.setRequestHeader('X-CSRF-Token', encodeURI(document.querySelector('meta[name="csrf-token"]').getAttribute('content')));
request.send('e=' + encodeURI(email));
request.onreadystatechange = function() {
if (request.readyState == 4) {
if (request.status == 200) {
f(JSON.parse(request.responseText));
} else {
f({error: request.status});
}
}
}
}
document.addEventListener('DOMContentLoaded', function() {
var fields = document.getElementsByClassName('user-field');
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var input = field.getElementsByTagName('input')[0];
var name = field.getElementsByClassName('user-name')[0];
}
}, false);
})();

812
app/assets/stylesheets/_application.scss

File diff suppressed because it is too large

11
app/assets/stylesheets/_settings.scss

@ -14,6 +14,11 @@ $colour-5: #02CA9E; // green
$white: #FFFEFE;
$black: #333;
$gray: #E8E8E8;
$light-gray: #EEE;
$mid-gray: #888;
// $red: #B24C63;
$red: #FF5A5F;
$link-colour: darken($colour-1, 13%);
@ -89,6 +94,10 @@ $link-colour: darken($colour-1, 13%);
}
}
@mixin text-stroke {
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
}
@mixin button {
position: relative;
display: inline-block;
@ -103,7 +112,7 @@ $link-colour: darken($colour-1, 13%);
@include default-box-shadow(top, 2);
overflow: hidden;
cursor: pointer;
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
@include text-stroke;
@include before {
content: '';

4
app/assets/stylesheets/bumbleberry-settings.json

@ -5,8 +5,8 @@
"chrome": ["51"]
},
"development": {
"and_chr": ["53"],
"chrome": ["53"],
"and_chr": ["54"],
"chrome": ["54"],
"edge": ["13"],
"firefox": ["44"],
"ie": ["11"],

36
app/controllers/admin_controller.rb

@ -0,0 +1,36 @@
require 'geocoder/calculations'
class AdminController < ApplicationController
def new
return do_404 unless logged_in? && current_user.administrator?
@this_conference = Conference.new
@page_title = 'articles.conferences.headings.new'
end
def edit
return do_404 unless logged_in? && current_user.administrator?
@this_conference = Conference.find_by!(slug: params[:slug])
@page_title = 'articles.conferences.headings.edit'
render 'new'
end
def save
conference = params[:id].present? ? Conference.find_by!(id: params[:id]) : Conference.new
if params[:button] == 'save'
city = City.search(params[:city])
conference.city_id = city.id
conference.conferencetype = params[:type]
conference.year = params[:year].to_i
conference.is_public = params[:is_public].present?
conference.is_featured = params[:is_featured].present?
conference.make_slug(true)
conference.save!
elsif params[:button] == 'delete'
conference.destroy
return redirect_to conferences_url
end
redirect_to conference_url(conference.slug)
end
end

127
app/controllers/application_controller.rb

@ -4,14 +4,14 @@ 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, :js_error, :admin_update]
before_filter :capture_page_info
helper_method :protect
@@test_host
@@test_location
@ -36,8 +36,18 @@ class ApplicationController < LinguaFrancaApplicationController
I18n.config.translator = current_user
I18n.config.callback = self
# get the current conference and set it globally
@conference = Conference.order("start_date DESC").first
# get the current conferences and set them globally
status_hierarchy = {
open: 1,
pre: 2,
closed: 3
}
@conferences = Conference.where(is_featured: true, is_public: true).order("start_date DESC").sort do |a, b|
status_hierarchy[(a.registration_status || :closed).to_sym] <=> status_hierarchy[(b.registration_status || :closed).to_sym]
end
# set the top conference
@conference = @conferences.first
# add some style sheets
@stylesheets ||= Array.new
@ -72,16 +82,7 @@ class ApplicationController < LinguaFrancaApplicationController
if @conference.workshop_schedule_published
@event_dlg = true
#view_context.add_inline_script :schedule
get_scheule_data(false)
# @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
@ -207,6 +208,13 @@ class ApplicationController < LinguaFrancaApplicationController
end
rescue_from StandardError do |exception|
handle_exception exception
# show the error page
error_500 exception
end
def handle_exception(exception)
# log the error
logger.info exception.to_s
logger.info exception.backtrace.join("\n")
@ -229,9 +237,14 @@ class ApplicationController < LinguaFrancaApplicationController
# raise the error if we are in development so that we can debug it
raise exception if Rails.env.development?
end
# show the error page
error_500 exception
def protect(&block)
begin
yield
rescue Exception => exception
handle_exception exception
end
end
def generate_confirmation(user, url, expiry = nil)
@ -403,6 +416,23 @@ class ApplicationController < LinguaFrancaApplicationController
redirect_to (params[:url] || '/')
end
def find_user
user = User.find_user(params[:e])
if user.present?
return render json: {
name: user.name,
email: user.email,
exists: true
}
end
render json: {
name: I18n.t('user.not_found'),
email: nil,
exists: false
}
end
def login_user(u)
auto_login(u)
end
@ -460,6 +490,38 @@ class ApplicationController < LinguaFrancaApplicationController
end
end
def set_success_message(message, is_ajax = false)
if is_ajax
@success_message = message
else
flash[:success_message] = message
end
end
def set_error_message(message, is_ajax = false)
if is_ajax
@error_message = message
else
flash[:error_message] = message
end
end
def set_error(field, error, is_ajax = false)
if is_ajax
@errors ||= {}
@errors[field] = error
else
flash[:errors] ||= {}
flash[:errors][field] = error
end
end
def set_flash_messages
@errors = flash[:errors] || {}
@warnings = flash[:warning] || []
@success_message = flash[:success_message]
@error_message = flash[:error_message] || []
end
def get_block_data
conference = @this_conference || @conference
@ -641,4 +703,39 @@ class ApplicationController < LinguaFrancaApplicationController
end
end
end
protected
def set_conference
@this_conference = Conference.find_by!(slug: params[:slug])
end
def set_conference_registration
@registration = logged_in? ? ConferenceRegistration.find_by(user_id: current_user.id, conference_id: @this_conference.id) : nil
end
def set_conference_registration!
@registration = set_conference_registration
raise ActiveRecord::PremissionDenied unless @registration.present?
end
def set_or_create_conference_registration
set_conference_registration
return @registration if @registration.present?
@registration ||= ConferenceRegistration.new(
conference: @this_conference,
user_id: current_user.id,
steps_completed: []
)
last_registration_data = ConferenceRegistration.where(user_id: current_user.id).order(created_at: :desc).limit(1).first
if last_registration_data.present?
if last_registration_data['languages'].present? && current_user.languages.blank?
current_user.languages = JSON.parse(last_registration_data['languages'])
current_user.save!
end
@registration.city = last_registration_data.city if last_registration_data.city.present?
end
end
end

1208
app/controllers/conference_administration_controller.rb

File diff suppressed because it is too large

1447
app/controllers/conferences_controller.rb

File diff suppressed because it is too large

355
app/controllers/workshops_controller.rb

@ -0,0 +1,355 @@
class WorkshopsController < ApplicationController
def workshops
set_conference
set_conference_registration!
@workshops = Workshop.where(:conference_id => @this_conference.id)
@my_workshops = Workshop.joins(:workshop_facilitators).where(:workshop_facilitators => {:user_id => current_user.id}, :conference_id => @this_conference.id)
render 'workshops/index'
end
def view_workshop
set_conference
set_conference_registration!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop
@translations_available_for_editing = []
I18n.backend.enabled_locales.each do |locale|
@translations_available_for_editing << locale if @workshop.can_translate?(current_user, locale)
end
@page_title = 'page_titles.conferences.View_Workshop'
@register_template = :workshops
render 'workshops/show'
end
def create_workshop
set_conference
set_conference_registration!
@workshop = Workshop.new
@languages = [I18n.locale.to_sym]
@needs = []
@page_title = 'page_titles.conferences.Create_Workshop'
@register_template = :workshops
render 'workshops/new'
end
def translate_workshop
@is_translating = true
@translation = params[:locale]
@page_title = 'page_titles.conferences.Translate_Workshop'
@page_title_vars = { language: view_context.language_name(@translation) }
@register_template = :workshops
edit_workshop
end
def edit_workshop
set_conference
set_conference_registration!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop.present?
@page_title ||= 'page_titles.conferences.Edit_Workshop'
@can_edit = @workshop.can_edit?(current_user)
@is_translating ||= false
if @is_translating
return do_404 if @translation.to_s == @workshop.locale.to_s || !I18n.backend.enabled_locales.include?(@translation.to_s)
return do_403 unless @workshop.can_translate?(current_user, @translation)
@title = @workshop._title(@translation)
@info = @workshop._info(@translation)
else
return do_403 unless @can_edit
@title = @workshop.title
@info = @workshop.info
end
@needs = JSON.parse(@workshop.needs || '[]').map &:to_sym
@languages = JSON.parse(@workshop.languages || '[]').map &:to_sym
@space = @workshop.space.to_sym if @workshop.space
@theme = @workshop.theme.to_sym if @workshop.theme
@notes = @workshop.notes
@register_template = :workshops
render 'workshops/new'
end
def delete_workshop
set_conference
set_conference_registration!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop.present?
return do_403 unless @workshop.can_delete?(current_user)
if request.post?
if params[:button] == 'confirm'
if @workshop
@workshop.workshop_facilitators.destroy_all
@workshop.destroy
end
return redirect_to register_step_path(@this_conference.slug, 'workshops')
end
return redirect_to view_workshop_url(@this_conference.slug, @workshop.id)
end
@register_template = :workshops
render 'workshops/delete'
end
def save_workshop
set_conference
set_conference_registration!
if params[:button].to_sym != :save
if params[:workshop_id].present?
return redirect_to view_workshop_url(@this_conference.slug, params[:workshop_id])
end
return redirect_to register_step_path(@this_conference.slug, 'workshops')
end
if params[:workshop_id].present?
workshop = Workshop.find(params[:workshop_id])
return do_404 unless workshop.present?
can_edit = workshop.can_edit?(current_user)
else
workshop = Workshop.new(:conference_id => @this_conference.id)
workshop.workshop_facilitators = [WorkshopFacilitator.new(:user_id => current_user.id, :role => :creator)]
can_edit = true
end
title = params[:title]
info = params[:info].gsub(/^\s*(.*?)\s*$/, '\1')
if params[:translation].present? && workshop.can_translate?(current_user, params[:translation])
old_title = workshop._title(params[:translation])
old_info = workshop._info(params[:translation])
do_save = false
unless title == old_title
workshop.set_column_for_locale(:title, params[:translation], title, current_user.id)
do_save = true
end
unless info == old_info
workshop.set_column_for_locale(:info, params[:translation], info, current_user.id)
do_save = true
end
# only save if the text has changed, if we want to make sure only to update the translator id if necessary
workshop.save_translations if do_save
elsif can_edit
workshop.title = title
workshop.info = info
workshop.languages = (params[:languages] || {}).keys.to_json
workshop.needs = (params[:needs] || {}).keys.to_json
workshop.theme = params[:theme] == 'other' ? params[:other_theme] : params[:theme]
workshop.space = params[:space]
workshop.notes = params[:notes]
workshop.needs_facilitators = params[:needs_facilitators].present?
workshop.save
# Rouge nil facilitators have been know to be created, just destroy them here now
WorkshopFacilitator.where(:user_id => nil).destroy_all
else
return do_403
end
redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
def toggle_workshop_interest
set_conference
set_conference_registration!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop
# save the current state
interested = workshop.interested? current_user
# remove all associated fields
WorkshopInterest.delete_all(:workshop_id => workshop.id, :user_id => current_user.id)
# creat the new interest row if we weren't interested before
WorkshopInterest.create(:workshop_id => workshop.id, :user_id => current_user.id) unless interested
if request.xhr?
render json: [
{
selector: '.interest-button',
html: view_context.interest_button(workshop)
},
{
selector: '.interest-text',
html: view_context.interest_text(workshop)
}
]
else
# go back to the workshop
redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
end
def facilitate_workshop
set_conference
set_conference_registration!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop
return do_403 if @workshop.facilitator?(current_user) || !current_user
@register_template = :workshops
render 'workshops/facilitate'
end
def facilitate_request
set_conference
set_conference_registration!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop
return do_403 if workshop.facilitator?(current_user) || !current_user
# create the request by making the user a facilitator but making their role 'requested'
WorkshopFacilitator.create(user_id: current_user.id, workshop_id: workshop.id, role: :requested)
UserMailer.send_mail :workshop_facilitator_request do
{
:args => [ workshop, current_user, params[:message] ]
}
end
redirect_to sent_facilitate_workshop_url(@this_conference.slug, workshop.id)
end
def sent_facilitate_request
set_conference
set_conference_registration!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop
return do_403 unless @workshop.requested_collaborator?(current_user)
@register_template = :workshops
render 'workshops/facilitate_request_sent'
end
def approve_facilitate_request
return do_403 unless logged_in?
set_conference
set_conference_registration!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop.present?
user_id = params[:user_id].to_i
action = params[:approve_or_deny].to_sym
user = User.find(user_id)
case action
when :approve
if workshop.active_facilitator?(current_user) && workshop.requested_collaborator?(User.find(user_id))
f = WorkshopFacilitator.find_by_workshop_id_and_user_id(
workshop.id, user_id)
f.role = :collaborator
f.save
UserMailer.send_mail :workshop_facilitator_request_approved, user.locale do
[ workshop, user ]
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
when :deny
if workshop.active_facilitator?(current_user) && workshop.requested_collaborator?(User.find(user_id))
WorkshopFacilitator.delete_all(
:workshop_id => workshop.id,
:user_id => user_id)
UserMailer.send_mail :workshop_facilitator_request_denied, user.locale do
[ workshop, user ]
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
when :remove
if workshop.can_remove?(current_user, user)
WorkshopFacilitator.delete_all(
:workshop_id => workshop.id,
:user_id => user_id)
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
when :switch_ownership
if workshop.creator?(current_user)
f = WorkshopFacilitator.find_by_workshop_id_and_user_id(
workshop.id, current_user.id)
f.role = :collaborator
f.save
f = WorkshopFacilitator.find_by_workshop_id_and_user_id(
workshop.id, user_id)
f.role = :creator
f.save
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
end
end
return do_403
end
def add_workshop_facilitator
set_conference
set_conference_registration!
user = User.find_by_email(params[:email])
# create the user if they don't exist and send them a link to register
unless user
user = User.create(email: params[:email])
generate_confirmation(user, register_path(@this_conference.slug))
end
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop && current_user
unless workshop.facilitator?(user)
WorkshopFacilitator.create(user_id: user.id, workshop_id: workshop.id, role: :collaborator)
UserMailer.send_mail :workshop_facilitator_request_approved, user.locale do
[ workshop, user ]
end
end
return redirect_to view_workshop_url(@this_conference.slug, params[:workshop_id])
end
def add_comment
set_conference
set_conference_registration!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop && current_user
if params[:button] == 'reply'
comment = Comment.find_by!(id: params[:comment_id].to_i, model_type: :workshops, model_id: workshop.id)
new_comment = comment.add_comment(current_user, params[:reply])
unless comment.user.id == current_user.id
UserMailer.send_mail :workshop_comment, comment.user.locale do
[ workshop, new_comment, comment.user ]
end
end
elsif params[:button] = 'add_comment'
new_comment = workshop.add_comment(current_user, params[:comment])
workshop.active_facilitators.each do | u |
unless u.id == current_user.id
UserMailer.send_mail :workshop_comment, u.locale do
[ workshop, new_comment, u ]
end
end
end
else
return do_404
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id, anchor: "comment-#{new_comment.id}")
end
end

298
app/helpers/application_helper.rb

@ -589,7 +589,7 @@ module ApplicationHelper
city = nil
region = nil
country = nil
if location.is_a?(Location)
if location.is_a?(Location) || location.is_a?(City)
country = location.country
region = location.territory
city = location.city
@ -639,7 +639,7 @@ module ApplicationHelper
location1.eql? location2
end
def show_errors(field, value)
def show_errors(field, value = nil)
return '' unless @errors && @errors[field].present?
error_txt = _"errors.messages.fields.#{field.to_s}.#{@errors[field]}", :s, vars: { value: value }
@ -780,6 +780,16 @@ module ApplicationHelper
return options
end
def month_select(value = nil, args = {})
options = (1..12).to_a.map { |month| [ (I18n.t "date.#{args[:format] || 'month_names'}")[month], month ] }
selectfield args[:name] || :month, value, options, args
end
def month_day_select(value = nil, args = {})
options = (1..31).to_a.map { |day| [ day, day ] }
selectfield args[:name] || :month_day, value, options, args
end
def day_select(value = nil, args = {})
selectfield :day, value, conference_days_options_list(:during, nil, args[:format]), args
end
@ -963,11 +973,41 @@ module ApplicationHelper
return options
end
def admin_steps
def admin_steps # deprecated
[:stats, :edit, :payment, :broadcast, :housing, :locations, :meals, :events, :workshop_times, :schedule]
end
def valid_admin_steps
def administration_steps
{
info: [:administrators, :dates, :description, :poster],
payment: [:payment_message, :suggested_amounts, :paypal],
registration: [:registration_status, :stats, :registrations, :broadcast],
housing: [:providers, :housing],
events: [:locations, :meals, :events],
schedule: [:workshop_times, :schedule, :publish_schedule]
}
end
def administration_sub_steps
{
location_edit: :locations,
event_edit: :events
}
end
def get_administration_group(administration_step)
admin_step = administration_step.to_sym
admin_step = administration_sub_steps[admin_step] if administration_sub_steps[admin_step].present?
administration_steps.each do | group, steps |
steps.each do | step |
return group if step == admin_step
end
end
return nil
end
def valid_admin_steps # deprecated
admin_steps + [:broadcast_sent, :organizations]
end
@ -985,6 +1025,10 @@ module ApplicationHelper
content_tag :ul, steps.html_safe, id: 'registration-admin-menu'
end
def admin_update_form(options = {}, &block)
form_tag(administration_update_path(@this_conference.slug, @admin_step), options, &block)
end
def interest_button(workshop)
interested = workshop.interested?(current_user) ? :remove_interest : :show_interest
id = "#{interested.to_s.gsub('_', '-')}-#{workshop.id}"
@ -1220,7 +1264,13 @@ module ApplicationHelper
end
end
def button_with_confirmation(button_name, confirmation_text, args = {})
def button_with_confirmation(button_name, confirmation_text = nil, args = {})
if confirmation_text.is_a? Hash
args = confirmation_text
confirmation_text = nil
end
confirmation_text ||= (_"forms.confirmations.#{button_name.to_s}", :p)
@confirmation_dlg ||= true
args[:data] ||= {}
args[:data][:confirmation] = true
@ -1243,8 +1293,113 @@ module ApplicationHelper
strip_tags(text.gsub('>', '> ')).gsub(/^(.{40,60})\s.*$/m, '\1&hellip;').html_safe
end
def translate_fields(object, field_options = {}, options = {})
html = ''
nav = ''
# set the selected locale
selected_locale = (options[:locale] || object.locale || I18n.locale).to_sym
I18n.backend.enabled_locales.each do | locale |
# ses if this should b the selected field
class_name = selected_locale == locale.to_sym ? 'selected' : nil
# add the locale to the nav
nav += content_tag(:li,
content_tag(:a, _("languages.#{locale}"), href: 'javascript:void(0)'),
class: class_name, data: { locale: locale }).html_safe
fields = ''
field_options.each do | name, __options |
_options = __options.deep_dup
# add the field
value = object.is_a?(Hash) ? object[locale.to_sym] : object.get_column_for_locale!(name, locale)
# use the default value if we need to
if _options[:default].present? && value.blank?
value = _(_options[:default], locale: locale)
end
_options[:index] = locale
_options[:lang] = locale
_options[:parent_options] = { lang: locale }
type = "#{_options[:type].to_s}"
_options.delete(:type)
fields += self.send(type, name, value, _options).html_safe
end
html += content_tag(:li, fields.html_safe, class: class_name, data: { locale: locale }).html_safe
end
if options[:class].nil?
options[:class] = []
elsif options[:class].is_a?(String)
options[:class] = [options[:class]]
end
options[:class] += ['translator', 'multi-field-translator']
(fieldset(nil, options) do
content_tag(:ul, nav.html_safe, class: 'locale-select').html_safe +
content_tag(:ul, html.html_safe, class: 'text-editors').html_safe
end).html_safe
end
def translate_textarea(name, object, property = nil, options = {})
html = ''
nav = ''
# see if options was passed in as property
if options.blank? && property.is_a?(Hash)
options = property
property = nil
end
# set the selected locale
selected_locale = (options[:locale] || object.locale || I18n.locale).to_sym
I18n.backend.enabled_locales.each do | locale |
# ses if this should b the selected field
class_name = selected_locale == locale.to_sym ? 'selected' : nil
# add the locale to the nav
nav += content_tag(:li,
content_tag(:a, _("languages.#{locale}"), href: 'javascript:void(0)'),
class: class_name, data: { locale: locale }).html_safe
# add the field
value = object.is_a?(Hash) ? object[locale.to_sym] : object.get_column_for_locale!(name, locale)
# use the default value if we need to
if options[:default].present? && value.blank?
value = _(options[:default], locale: locale)
end
html += content_tag(:li, textarea(name, value, {
label: false,
edit_on: options[:edit_on],
parent_options: {
lang: locale
},
index: locale
}).html_safe, class: class_name, data: { locale: locale }).html_safe
end
if options[:class].nil?
options[:class] = []
elsif options[:class].is_a?(String)
options[:class] = [options[:class]]
end
options[:class] += ['translator']
(fieldset(name, options) do
content_tag(:ul, nav.html_safe, class: 'locale-select').html_safe +
content_tag(:ul, html.html_safe, class: 'text-editors').html_safe
end).html_safe
end
def textarea(name, value = nil, options = {})
id = name.to_s.gsub('[', '_').gsub(']', '')
id = unique_id(name)
label_id = "#{id}-label"
description_id = nil
html = ''
@ -1281,8 +1436,9 @@ module ApplicationHelper
options[:short] === true ? :short : nil
].compact
html_name = name.to_s + (options[:index] ? "[#{options[:index]}]" : '')
if options[:plain]
html += (text_area_tag name, value,
html += (text_area_tag html_name, value,
id: id,
lang: options[:lang],
aria: aria,
@ -1291,7 +1447,7 @@ module ApplicationHelper
else
html += content_tag(:div, value.present? ? value.html_safe : '',
id: id,
data: { name: name, 'edit-on': options[:edit_on] || :load },
data: { name: html_name, 'edit-on': options[:edit_on] || :load },
lang: options[:lang],
aria: aria,
tabindex: 0,
@ -1304,37 +1460,66 @@ module ApplicationHelper
add_inline_script :editor
end
html = content_tag(:div, html.html_safe, class: ['text-area-field', 'input-field']).html_safe
parent_options = options[:parent_options] || {}
if parent_options[:class].nil?
parent_options[:class] = []
elsif parent_options[:class].is_a?(String)
parent_options[:class] = [parent_options[:class]]
end
parent_options[:class] += ['text-area-field', 'input-field']
html = content_tag(:div, html.html_safe, parent_options).html_safe
html += _original_content(options[:original_value], options[:original_lang]) if options[:original_value].present?
return html.html_safe
end
def fieldset(name, options = {}, &block)
def fieldset(name = nil, options = {}, &block)
html = ''
label_id = nil
label = ''
description = ''
description_id = nil
errors = ''
if options[:heading].present?
label_id ||= "#{name.to_s}-label"
html += content_tag(:h3, _(options[:heading], :t, vars: options[:vars] || {}), id: label_id)
if name.present?
if options[:label] != false
label = content_tag(:legend,
_((
options[:label].is_a?(String) ?
options[:label] :
"forms.labels.generic.#{name}"), :t, vars: options[:vars] || {}))
end
if options[:help].present?
description_id ||= "#{name.to_s}-desc"
html += content_tag(:div, _(options[:help], :s, 2), class: 'input-field-help', id: description_id)
description_id = unique_id("#{name.to_s}-desc")
description = content_tag(:div, _(options[:help], :s, 2), class: 'input-field-help', id: description_id)
end
(html + content_tag(:fieldset, content_tag(:div, class: :fieldgroup, &block).html_safe,
aria: {
labelledby: label_id,
describedby: description_id
}
errors = (show_errors name)
end
html = label + errors + description + content_tag(:div, class: :fieldgroup, &block)
aria = description_id.present? ? { describedby: description_id } : nil
(content_tag(:fieldset, html.html_safe,
aria: aria,
class: ((options[:class] || []) + [
options[:inline] ? :inline : nil,
options[:inline_label] ? 'inline-label' : nil,
errors.present? ? 'has-error' : nil
]).compact
)
).html_safe
end
def selectfield(name, value, select_options, options = {})
unless select_options.first.is_a?(Array)
so = select_options
select_options = []
so.each do | opt |
select_options << [ I18n.t("forms.options.#{name.to_s}.#{opt.to_s}"), opt]
end
end
textfield(name, value, options.merge({type: :select, options: select_options}))
end
@ -1350,10 +1535,23 @@ module ApplicationHelper
textfield(name, value, options.merge({type: :search}))
end
def userfield(name, value, options = {})
# eventually this will be a dynamic field to find users, for now we'll just use emails
# add_inline_script :userfield
emailfield(name, value, options)# .merge({
# parent_options: { class: ['user-field'] },
# after: content_tag(:div, '', class: 'user-name')
# }))
end
def emailfield(name, value, options = {})
textfield(name, value, options.merge({type: :email}))
end
def filefield(name, value, options = {})
textfield(name, value, options.merge({type: :file}))
end
def passwordfield(name, value, options = {})
textfield(name, value, options.merge({type: :password}))
end
@ -1375,16 +1573,34 @@ module ApplicationHelper
html += show_errors name, value
if options[:label].present?
html += label_tag(id) do
_(options[:label], :t, vars: options[:vars] || {})
inside_label = ''
if options[:type] == :file
inside_label = (content_tag(:div, class: 'file-field-selector') do
(options[:preview] ? content_tag(:img, nil, src: value.present? ? value.url : nil).html_safe : '').html_safe +
content_tag(:div, (value.present? ? File.basename(value.url) : (_'forms.labels.generic.no_file_selected')), class: 'file-field-name ' + (value.present? ? 'selected' : 'unselected')).html_safe +
content_tag(:a, (_'forms.actions.generic.select_file'), class: :button)
end)
end
label_text = nil
if options[:label].present?
label_text = _(options[:label], :t, vars: options[:vars] || {})
elsif options[:label] != false
html += label_tag id, (_"forms.labels.generic.#{name}")
elsif options[:type] == :select
label_text = (_"forms.labels.generic.#{name}")
elsif options[:type] == :select || options[:type] == :file
# add an empty label so that the drop down button will still appear
html += label_tag id, ''
label_text = ''
end
label_options = {}
# let the label be selected if the input is hidden
label_options[:tabindex] = 0 if options[:type] == :file
unless label_text.nil?
html += label_tag id, (label_text + inside_label).html_safe
end
input_options = {
id: id,
required: options[:required],
@ -1419,11 +1635,19 @@ module ApplicationHelper
option_list = ('<option value="">&nbsp;</option>' + option_list).html_safe
end
html += select_tag(name, option_list, input_options)
when :file
add_inline_script :filefield
input_options[:tabindex] = '-1'
html += off_screen(file_field_tag name, input_options)
else
input_options[:autocomplete] = 'off' if options[:type] == :search
html += send("#{(options[:type] || :text).to_s}_field_tag", name, value, input_options)
end
if options[:after].present?
html += options[:after].html_safe
end
html = content_tag(:div, html.html_safe,
class: [
"#{(options[:type] || :text).to_s}-field",
@ -1435,7 +1659,7 @@ module ApplicationHelper
options[:full] ? 'full' : nil,
options[:inline_label] ? 'inline-label' : nil,
(@errors || {})[name].present? ? 'has-error' : nil
].compact)
].compact + (((options[:parent_options] || {})[:class]) || []))
html += _original_content(options[:original_value], options[:original_lang]) if options[:original_value].present?
@ -1489,8 +1713,14 @@ module ApplicationHelper
boxes_html = ''
labels = nil
is_single = !values.is_a?(Array)
unless boxes.length > 0 && boxes.first.is_a?(Integer)
if boxes.length > 0
if boxes.first.is_a?(Array)
labels = boxes.map(&:first)
boxes = boxes.map(&:last)
end
elsif !boxes.first.is_a?(Integer)
values = values.present? ? values.map(&:to_s) : [] unless is_single
boxes = boxes.map(&:to_s)
end
@ -1498,7 +1728,7 @@ module ApplicationHelper
# convert the required value into a pure boolean
required = !!options[:required]
boxes.each do | box |
boxes.each_with_index do | box, i |
checked = (is_single ? values.present? : values.include?(box))
values -= [box] if checked && !is_single
id = nil
@ -1514,7 +1744,9 @@ module ApplicationHelper
# we only need the required attribute on one element
required = false
if is_single
if labels.present?
label = labels[i]
elsif is_single
label = _(label_key.to_s)
elsif box.is_a?(Integer)
label = I18n.t(label_key.to_s)[box]
@ -1920,7 +2152,7 @@ module ApplicationHelper
other: 2
},
required_columns: [:name, :email],
editable: administration_update_path(@this_conference.slug, :stats),
editable: administration_update_path(@this_conference.slug, @admin_step),
column_options: @column_options
}
end
@ -1954,7 +2186,7 @@ module ApplicationHelper
User.AVAILABLE_LANGUAGES.map { |l| "language_#{l}".to_sym } +
ConferenceRegistration.all_spaces +
ConferenceRegistration.all_considerations,
editable: administration_update_path(@this_conference.slug, :stats),
editable: administration_update_path(@this_conference.slug, @admin_step),
column_options: @column_options
}
end

77
app/models/city.rb

@ -0,0 +1,77 @@
require 'geocoder'
require 'geocoder/railtie'
require 'geocoder/calculations'
Geocoder::Railtie.insert
class City < ActiveRecord::Base
geocoded_by :address
translates :city
reverse_geocoded_by :latitude, :longitude, :address => :full_address
after_validation :geocode, if: ->(obj){ obj.country_changed? or obj.territory_changed? or obj.city_changed? or obj.latitude.blank? or obj.longitude.blank? }
def address
([city!, territory, country] - [nil, '']).join(', ')
end
def get_translation(locale)
location = Geocoder.search(address, language: locale.to_s).first
location.data['address_components'].each do | component |
if component['types'].first == 'locality'
return component['short_name']
end
end
return nil
end
def translate_city(locale)
translation = get_translation(locale)
set_column_for_locale(:city, locale, translation)
save!
return translation
end
def self.search(str)
cache = CityCache.search(str)
# return the city if this search is in our cache
return cache.city if cache.present?
# look up the city in the geocoder
location = Geocoder.search(str, language: 'en').first
# see if the city is already present in our database
city = City.find_by_place_id(location.data['place_id'])
# return the city if we found it in the db already
return city if city.present?
# otherwise build a new city
component_alises = {
'locality' => :city,
'administrative_area_level_1' => :territory,
'country' => :country
}
city_data = {
locale: :en,
latitude: location.data['geometry']['location']['lat'],
longitude: location.data['geometry']['location']['lng'],
place_id: location.data['place_id']
}
location.data['address_components'].each do | component |
property = component_alises[component['types'].first]
city_data[property] = component['short_name'] if property.present?
end
# save the new city
city = City.new(city_data)
city.save!
# and return it
return city
end
end

9
app/models/city_cache.rb

@ -0,0 +1,9 @@
class CityCache < ActiveRecord::Base
self.table_name = :city_cache
belongs_to :city
def self.search(str)
CityCache.find_by_search(str.downcase)
end
end

79
app/models/conference.rb

@ -5,27 +5,47 @@ class Conference < ActiveRecord::Base
mount_uploader :poster, PosterUploader
belongs_to :conference_type
belongs_to :city
has_many :conference_host_organizations, :dependent => :destroy
has_many :organizations, :through => :conference_host_organizations
has_many :conference_host_organizations, dependent: :destroy
has_many :organizations, through: :conference_host_organizations
has_many :conference_administrators, dependent: :destroy
has_many :administrators, through: :conference_administrators, source: :user
has_many :event_locations
#has_many :conference_registration_form_fields, :order => 'position ASC', :dependent => :destroy#, :class_name => '::ConferenceRegistrationFormField'
#has_many :registration_form_fields, :through => :conference_registration_form_fields
has_many :workshops
accepts_nested_attributes_for :conference_host_organizations, :reject_if => proc {|u| u[:organization_id].blank?}, :allow_destroy => true
accepts_nested_attributes_for :conference_host_organizations, reject_if: proc {|u| u[:organization_id].blank?}, allow_destroy: true
before_create :make_slug
def to_param
slug
end
def host_organization?(org)
return false unless org.present?
org_id = org.is_a?(Organization) ? org.id : org
organizations.each do |o|
return true if o.id = org_id
end
return false
end
def host?(user)
return false unless user.present?
if user.present?
return true if user.administrator?
conference_administrators.each do |u|
return true if user.id == u.id
end
organizations.each do |o|
return true if o.host?(user)
end
end
return false
end
@ -39,6 +59,7 @@ class Conference < ActiveRecord::Base
end
def location
return nil unless organizations.present?
organizations.first.location
end
@ -64,8 +85,52 @@ class Conference < ActiveRecord::Base
write_attribute :registration_status, new_registration_status.to_s
end
def make_slug(reset = false)
if reset
self.slug = nil
end
self.slug ||= Conference.generate_slug(
conferencetype || :annual,
conference_year,
city_name.gsub(/\s/, '')
)
end
def city_name
return city.city if city.present?
return location.present? ? location.city : nil
end
def conference_year
self.year || (end_date.present? ? end_date.year : nil)
end
def over?
return false unless end_date.present?
return end_date < DateTime.now
end
def self.default_payment_amounts
[25, 50, 100]
end
def self.conference_types
{
annual: '%{city}%{year}',
n: 'North%{year}',
s: 'South%{year}',
e: 'East%{year}',
w: 'West%{year}',
ne: 'Northeast%{year}',
nw: 'Northwest%{year}',
se: 'Southeast%{year}',
sw: 'Southwest%{year}'
}
end
def self.generate_slug(type, year, city)
Conference.conference_types[(type || :annual).to_sym].gsub('%{city}', city).gsub('%{year}', year.to_s)
end
end

4
app/models/conference_administrator.rb

@ -0,0 +1,4 @@
class ConferenceAdministrator < ActiveRecord::Base
belongs_to :user
belongs_to :conference
end

2
app/models/conference_registration.rb

@ -30,7 +30,7 @@ class ConferenceRegistration < ActiveRecord::Base
end
def status(was = false)
return :unregistered if user.firstname.blank? || self.send(was ? :city_was : :city).blank?
return :unregistered if user.nil? || user.firstname.blank? || self.send(was ? :city_was : :city).blank?
return :registered if self.send(was ? :housing_was : :housing).present? || (self.send(was ? :can_provide_housing_was : :can_provide_housing) && (self.send(was ? :housing_data_was : :housing_data) || {})['availability'].present?)
return :preregistered
end

12
app/models/organization.rb

@ -4,10 +4,10 @@ class Organization < ActiveRecord::Base
mount_uploader :cover, CoverUploader
has_many :locations_organization
has_many :locations, :through => :locations_organization
has_many :locations, through: :locations_organization
has_many :user_organization_relationships, :dependent => :destroy
has_many :users, :through => :user_organization_relationships
has_many :user_organization_relationships, dependent: :destroy
has_many :users, through: :user_organization_relationships
accepts_nested_attributes_for :locations, :reject_if => proc {|l| l[id].blank?}
accepts_nested_attributes_for :user_organization_relationships, :reject_if => proc {|u| u[:user_id].blank?}, :allow_destroy => true
@ -62,6 +62,12 @@ class Organization < ActiveRecord::Base
s
end
def self.find_by_city(city)
Organization.joins(:locations).where(locations: {
city_id: city.is_a?(City) ? city.id : city
})
end
private
def make_slug
if !self.slug

5
app/models/user.rb

@ -9,6 +9,7 @@ class User < ActiveRecord::Base
has_many :user_organization_relationships
has_many :organizations, through: :user_organization_relationships
has_many :conferences, through: :conference_administrators
has_many :authentications, :dependent => :destroy
accepts_nested_attributes_for :authentications
@ -59,4 +60,8 @@ class User < ActiveRecord::Base
return user
end
def self.find_user(email)
User.where('lower(email) = ?', email.downcase).first
end
end

6
app/uploaders/avatar_uploader.rb

@ -25,13 +25,13 @@ class AvatarUploader < CarrierWave::Uploader::Base
end
# Provide a default URL as a default if there hasn't been a file uploaded:
def default_url
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
#"/images/fallback/" + [version_name, "default.png"].compact.join('_')
"http://placehold.it/" + (@@sizes[version_name] || [300, 300]).join('x')
end
# "http://placehold.it/" + (@@sizes[version_name] || [300, 300]).join('x')
#end
# Process files as they are uploaded:
# process :scale => [200, 300]

24
app/views/admin/new.html.haml

@ -0,0 +1,24 @@
- body_class 'banner-bottom'
= render :partial => 'application/header', :locals => {:page_group => :administration, :page_key => 'Administration', :image_file => 'admin.jpg'}
%article
= row do
= form_tag save_conference_path, class: 'composition' do
= columns(medium: 12) do
%h2=_@page_title, :t
= hidden_field_tag :id, @this_conference.id if @this_conference.id.present?
= columns(medium: 12) do
= textfield :city, location(@this_conference.city), required: true, big: true
= columns(medium: 12, class: 'flex-column') do
= selectfield :type, @this_conference.conferencetype, Conference.conference_types.keys.map { |k| [(_"forms.options.conferences.types.#{k}"), k]}, required: true, stretch: true
= numberfield :year, @this_conference.conference_year || Date.today.year, required: true
= columns(medium: 6) do
= checkbox :is_public, @this_conference.is_public != false, 'forms.labels.generic.is_public'
= columns(medium: 6) do
= checkbox :is_featured, @this_conference.is_featured != false, 'forms.labels.generic.is_featured'
= columns(medium: 12) do
.actions.next-prev
= button_tag :save, value: :save
- if @this_conference.id.present?
= button_with_confirmation :delete, value: :delete, class: 'delete'

4
app/views/application/_header.html.haml

@ -12,9 +12,9 @@
= cover.html_safe if cover
- if @page_title.present? || defined?(page_group)
- content_for :title do
=@page_title.present? ? I18n.t(@page_title, @page_title_vars) : I18n.t("page_titles.#{page_group.to_s}.#{page_key.to_s}")
= I18n.t(@page_title || "page_titles.#{page_group.to_s}.#{page_key.to_s}", @page_title_vars)
= row do
= columns do
%h1=_(@main_title || "page_titles.#{page_group.to_s}.#{page_key.to_s}", :t, @main_title_vars)
%h1=_(@main_title || "page_titles.#{page_group.to_s}.#{page_key.to_s}", :t, @main_title_vars || (@page_title_vars.present? && @page_title.blank? ? { vars: @page_title_vars } : nil))
- content_for :og_image do
= image

22
app/views/application/home.html.haml

@ -1,17 +1,5 @@
- this_is_the_front_page
- if @conference
= render 'conferences/header'
%article
= row do
= columns(medium: 10, push: {medium: 1}) do
%h2=_!@conference.title
= richtext @conference.info
- if @conference.registration_status == :open
- if @conference.workshop_schedule_published
- add_inline_script :home_schedule
%h3=_'articles.workshops.headings.Schedule'
= render 'conferences/admin/schedule'
- else
%h3=_'articles.workshops.headings.Proposed_Workshops'
%p=_'articles.workshops.paragraphs.Proposed_Workshops'
= render 'workshops/workshop_previews', :workshops => (@conference.workshops.sort { |a, b| a.title.downcase <=> b.title.downcase })
- content_for :og_image do
= @conference.poster.full.url || image_path('default_poster.jpg')
- if @conferences
- @conferences.each do | conference |
= render 'conferences/conference', conference: conference, links: [ :read_more, :register ]

41
app/views/conference_administration/_administrators.html.haml

@ -0,0 +1,41 @@
= columns(large: 8, push: { large: 2}) do
%h3=_'articles.admin.info.headings.Host_Organizations'
%p=_'articles.admin.info.descriptions.Host_Organizations', vars: { city_name: @this_conference.city.city }
= admin_update_form do
= checkboxes :organizations, (@organizations.map { |org| [org.name, org.id] }), @this_conference.organizations.map(&:id), 'test.test', vertical: true, big: true
.actions.right.small
= button_tag :save, value: :set_organizations
- @this_conference.organizations.each do | organization |
%h4=organization.name
- if organization.users.present?
.details.org-members
- organization.users.each do | user |
= raw_data_set(:h5, user.name) do
= user.email
- unless user.id == current_user.id && !current_user.administrator?
= admin_update_form class: [:inline, :right] do
= hidden_field_tag :user_id, user.id
= hidden_field_tag :org_id, organization.id
= button_tag :remove_member, value: :remove_org_member, class: [:small, :delete]
= admin_update_form class: 'mini-flex-form' do
= hidden_field_tag :org_id, organization.id
= emailfield :email, nil, required: true
= button_tag :add_member, value: :add_org_member, class: :small
%h3=_'articles.admin.info.headings.External_Administrators'
%p=_'articles.admin.info.descriptions.External_Administrators'
- if @this_conference.administrators.present?
.details.org-members
- @this_conference.administrators.each do | user |
= raw_data_set(:h5, user.name) do
= user.email
- unless user.id == current_user.id && !current_user.administrator?
= admin_update_form class: [:inline, :right] do
= hidden_field_tag :user_id, user.id
= button_tag :remove_member, value: :remove_administrator, class: [:small, :delete]
= admin_update_form class: 'mini-flex-form' do
= userfield :email, nil, required: true
-#= emailfield :email, nil, required: true
= button_tag :add_member, value: :add_administrator, class: :small
= columns(large: 2) do
&nbsp;

23
app/views/conference_administration/_broadcast.html.haml

@ -0,0 +1,23 @@
= columns(medium: 12) do
= admin_update_form do
- if @broadcast_step == :preview || @broadcast_step == :test
= hidden_field_tag :subject, @subject
= hidden_field_tag :body, @body
= hidden_field_tag :send_to, @send_to
- if @broadcast_step == :preview
%p= _'articles.conference_registration.paragraphs.admin.broadcast.test', vars: { send_to_count: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }
- else
.warning-info.make-room= _'articles.conference_registration.paragraphs.admin.broadcast.preview', vars: { send_to_count: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }
.test-preview
%h3=@subject
= richtext @body, 4
.actions.right
= button_tag :test, value: :test, class: :secondary if @broadcast_step == :preview
= button_with_confirmation :send, (_'modals.admin.broadcast.confirm', vars: { number: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }), value: :send, class: :delete if @broadcast_step == :test
= button_tag :edit, value: :edit
- else
= selectfield :send_to, nil, broadcast_options, full: true
= textfield :subject, @subject, required: true, big: true
= textarea :body, @body, lang: @this_conference.locale, edit_on: :focus
.actions.right
= button_tag :preview, value: :preview

0
app/views/conferences/admin/_broadcast_sent.html.haml → app/views/conference_administration/_broadcast_sent.html.haml

17
app/views/conference_administration/_dates.html.haml

@ -0,0 +1,17 @@
= admin_update_form do
= row do
= columns(medium: 6, push: { medium: 1 }) do
= fieldset :start_date, inline: true, inline_label: true do
= month_select @start_month, name: :start_month, label: false
= month_day_select @start_day, name: :start_day, label: false
= row do
= columns(medium: 6, push: { medium: 1 }) do
= fieldset :end_date, inline: true, inline_label: true do
= month_select @end_month, name: :end_month, label: false
= month_day_select @end_day, name: :end_day, label: false
= row do
= columns(medium: 6, push: { medium: 1 }) do
.actions
= button_tag :save, value: :save

5
app/views/conference_administration/_description.html.haml

@ -0,0 +1,5 @@
= columns(medium: 12) do
= admin_update_form do
= translate_textarea :info, @this_conference, label: 'articles.conference_registration.headings.admin.edit.info', help: 'articles.conference_registration.paragraphs.admin.edit.info', edit_on: :focus
.actions.right
= button_tag :save, value: :save

41
app/views/conference_administration/_events.html.haml

@ -0,0 +1,41 @@
- if @this_conference.event_locations.blank?
= columns(medium: 12) do
.warning-info=_'articles.admin.events.no_locations_warning'
- else
= columns(medium: 12) do
- if @events.present? && @event.id.blank?
%table.events.admin-edit
%tr
%th=_'forms.labels.generic.title'
%th=_'forms.labels.generic.event_location'
%th=_'forms.labels.generic.day'
%th=_'forms.labels.generic.time'
%th=_'forms.labels.generic.time_span'
%th.form
- @events.each do | event |
%tr
%th=event.title
%td=_!(event.event_location.present? ? event.event_location.title : '')
%td=date(event.start_time.to_date, :weekday)
%td=time(event.start_time, :short)
%td=hours(event.start_time, event.end_time)
%td.form
= admin_update_form do
= hidden_field_tag :id, event.id
= link_to (_'forms.actions.generic.edit'), edit_event_path(@this_conference, event.id), class: [:button, :small, :modify]
= button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: event.title }), value: :delete, class: [:delete, :small]
= columns(medium: 12) do
%h3=_"articles.admin.locations.headings.#{@event.id.present? ? 'edit' : 'add'}_event", :t
= admin_update_form do
= hidden_field_tag :id, @event.id if @event.id.present?
.flex-inputs
= location_select @event.event_location_id, small: true, stretch: true
= day_select @day, small: true, format: :weekday
= hour_select @time, small: true
= length_select @length, small: true
= translate_fields @event, { title: { type: :textfield, big: true, label: 'forms.labels.generic.title' }, info: { type: :textarea, label: 'forms.labels.generic.info', edit_on: :focus } }
.actions.next-prev
= button_tag :save, value: :save
= button_tag :cancel, value: :cancel, class: :subdued, formnovalidate: true if @event.id.present?

11
app/views/conference_administration/_hosts_table.html.haml

@ -0,0 +1,11 @@
.guests-housed
%h5 Guests Housed:
.data="#{@guests_housed} / #{@guests.size}"
%table.hosts.admin-edit
- @hosts.each do | id, registration |
%tr.host
%th
.name=registration.user.name
.address=registration.housing_data['address']
%td.inner-table{colspan: 2}=host_guests_table(registration)

10
app/views/conference_administration/_housing.html.haml

@ -0,0 +1,10 @@
- add_inline_script :housing
= columns(medium: 12) do
= admin_update_form id: 'housing-table-form' do
#housing-table= render partial: 'hosts_table'
#guest-selector
= admin_update_form class: 'guest-dlg', id: 'guest-list-table' do
%h3 Select a Guest
#table
.actions
= link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, @admin_step, :format => :xlsx), class: [:button, :download]

42
app/views/conference_administration/_locations.html.haml

@ -0,0 +1,42 @@
- unless @location.present?
- if @locations.present?
= columns(medium: 12) do
%table.locations.admin-edit
%tr
%th=_'forms.labels.generic.title'
%th=_'forms.labels.generic.address'
%th=_'articles.workshops.headings.space'
%th=_'articles.admin.locations.headings.amenities'
%th.form
- @locations.each do | location |
%tr
%th=_!(location.title || '')
%td=location_link location
%td=location.space.present? ? (_"workshop.options.space.#{location.space}") : ''
%td
- amenities = location.amenities.present? ? JSON.parse(location.amenities) : []
=_!(amenities.collect { |amenity| _"workshop.options.needs.#{amenity}" }).join(', ')
%td.form
= admin_update_form do
= hidden_field_tag :id, location.id
= link_to (_'forms.actions.generic.edit'), edit_location_path(@this_conference, location.id), class: [:button, :small, :modify]
= button_with_confirmation :delete, (_'modals.admin.generic.delete.confirm', :p, vars: { title: location.title }), value: :delete, class: [:delete, :small]
= admin_update_form do
= columns(medium: 12) do
%h5=_"articles.admin.locations.headings.#{@location.present? ? 'edit' : 'add'}_location", :t
= hidden_field_tag :id, @location.id if @location.present?
= textfield :title, @location.present? ? @location.title : nil, required: true, big: true, help: 'articles.admin.locations.paragraphs.title'
.flex-column.address-form
= textfield :address, @location.present? ? @location.address : nil, required: true, help: 'articles.admin.locations.paragraphs.address', stretch: true
.city=location(@this_conference.city)
= columns(medium: 6) do
= radiobuttons :space, EventLocation.all_spaces, @space, 'workshop.options.space', vertical: true, heading: 'articles.workshops.headings.space', required: true, help: 'articles.admin.locations.paragraphs.space'
= columns(medium: 6) do
= checkboxes :needs, EventLocation.all_amenities, @amenities || [], 'workshop.options.needs', vertical: true, heading: 'articles.admin.locations.headings.amenities', help: 'articles.admin.locations.paragraphs.amenities'
= columns(medium: 12) do
.actions.next-prev
- if @location.present?
= button_tag :save, value: :save
= button_tag :cancel, value: :cancel, class: :subdued, formnovalidate: true
- else
= button_tag :create, value: :create

35
app/views/conference_administration/_meals.html.haml

@ -0,0 +1,35 @@
= columns(medium: 12) do
- if @this_conference.event_locations.present?
- if @this_conference.meals.present?
%table.meals.admin-edit
%tr
%th=_'forms.labels.generic.title'
%th=_'forms.labels.generic.info'
%th=_'forms.labels.generic.event_location'
%th=_'forms.labels.generic.day'
%th=_'forms.labels.generic.time'
%th.form
- @meals.each do | time, meal |
%tr
%th
=_!(meal['title'] || '')
%td=_!(meal['info'] || '')
%td=_!location_name(meal['location'].to_i)
%td=date(meal['day'], :weekday)
%td=time(meal['time'].to_f)
%td.form
= admin_update_form do
= hidden_field_tag :meal, time
= button_tag :delete, value: :delete, class: [:small, :delete]
= admin_update_form do
%h3=_'articles.admin.locations.headings.add_meal', :t
.flex-inputs
= location_select nil, small: true, stretch: true
= day_select nil, small: true, format: :weekday
= hour_select nil, small: true
= textfield :title, nil, required: true, big: true, help: 'articles.admin.locations.paragraphs.meal_title'
= textfield :info, nil, help: 'articles.admin.locations.paragraphs.meal_info'
.actions.next-prev
= button_tag :add_meal, value: :add_meal
- else
.warning-info=_'articles.admin.meals.no_locations_warning'

6
app/views/conference_administration/_payment_message.html.haml

@ -0,0 +1,6 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, @admin_step) do
= translate_textarea :payment_message, @this_conference, default: 'articles.conference_registration.paragraphs.Payment', help: 'articles.conference_registration.paragraphs.admin.payment.message', edit_on: :focus, short: true
.actions.right
= button_tag :save, value: :save

8
app/views/conference_administration/_paypal.html.haml

@ -0,0 +1,8 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, @admin_step) do
= emailfield :paypal_email_address, @this_conference.paypal_email_address || @this_conference.email_address || (@this_conference.organizations.present? && @this_conference.organizations.first.present? ? @this_conference.organizations.first.email_address : nil)
= textfield :paypal_username, @this_conference.paypal_username
= passwordfield :paypal_password, @this_conference.paypal_password
= textfield :paypal_signature, @this_conference.paypal_signature
.actions.right
= button_tag :save, value: :save

5
app/views/conference_administration/_poster.html.haml

@ -0,0 +1,5 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, :poster), multipart: true do
= filefield :poster, @this_conference.poster, required: true, label: false, preview: true
.actions.left
= button_tag :upload, value: :upload, id: 'upload-file'

2
app/views/conference_administration/_providers.html.haml

@ -0,0 +1,2 @@
= columns(medium: 12) do
TO COME

8
app/views/conference_administration/_publish_schedule.html.haml

@ -0,0 +1,8 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, @admin_step) do
- if @this_conference.workshop_schedule_published
%p=_'articles.conference_registration.paragraphs.admin.schedule.published', :p
.actions= button_tag :un_publish, value: :publish, class: :delete
- else
%p=_'articles.conference_registration.paragraphs.admin.schedule.un_published', :p
.actions= button_tag :publish, value: :publish

5
app/views/conference_administration/_registration_status.html.haml

@ -0,0 +1,5 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, @admin_step) do
= selectfield :registration_status, @this_conference.registration_status || 'closed', registration_status_options_list, inline_label: true
.actions.left
= button_tag :save, value: :save

17
app/views/conference_administration/_registrations.html.haml

@ -0,0 +1,17 @@
- add_inline_script :registrations
= columns(medium: 12) do
.goes-fullscreen#registrations-table
.flex-column
= searchfield :search, nil, big: true, stretch: true
%a.button{data: { expands: 'registrations-table' }}='expand'
%a.button.delete{data: { contracts: 'registrations-table' }}='close'
%a.button.modify{data: { 'opens-modal': 'new-registration' }}='+'
.table-scroller
= html_table @excel_data, registrations_table_options
= admin_update_form id: 'new-registration', class: 'modal-edit' do
.modal-edit-overlay{data: { 'closes-modal': 'new-registration' }}
.modal-edit-content
= html_edit_table @excel_data, registrations_edit_table_options
.actions.right
%a.button.subdued{data: { 'closes-modal': 'new-registration' }}='Cancel'
= button_tag :save, value: :save, class: :modify

85
app/views/conference_administration/_schedule.html.haml

@ -0,0 +1,85 @@
= columns(medium: 12) do
- conference = @this_conference || @conference
- if conference.event_locations.blank? && @entire_page
.warning-info=_'articles.admin.schedule.no_locations_warning'
- else
- add_inline_script :schedule if @entire_page
#schedule-preview
- @schedule.each do | day, data |
%h4=date(day, :weekday)
%table.schedule{class: [data[:locations].present? ? 'has-locations' : 'no-locations', "locations-#{data[:num_locations]}"]}
- if data[:locations].present? && data[:locations].values.first != :add
%thead
%tr
%th.corner
- data[:locations].each do | id, location |
%th=location.is_a?(Symbol) ? '' : location.title
%tbody
- data[:times].each do | time, time_data |
%tr
- rowspan = (time_data[:length] * 2).to_i
%th=time(time)
- if time_data[:type] == :workshop
- data[:locations].each do | id, location |
- if time_data[:item][:workshops][id].present?
- workshop = time_data[:item][:workshops][id][:workshop]
- status = time_data[:item][:workshops][id][:status]
- else
- workshop = status = nil
%td{class: [time_data[:type], workshop.present? ? :filled : :open], rowspan: rowspan, data: workshop.present? ? nil : { block: time_data[:item][:block], day: day, location: id }}
- if workshop.present? && workshop.event_location.present?
= link_to view_workshop_path(@conference.slug, workshop.id), class: 'event-detail-link' do
.details
.title=workshop.title
%template.event-details{data: { href: view_workshop_path(@conference.slug, workshop.id) }}
%h1.title=workshop.title
%p.address
= workshop.event_location.title + _!(': ')
= location_link workshop.event_location
.workshop-description= richtext workshop.info, 1
- if @can_edit
= form_tag administration_update_path(conference.slug, @admin_step), class: 'deschedule-workshop' do
.status
.conflict-score
%span.title Conflicts:
%span.value="#{status[:conflict_score]} / #{workshop.interested.size}"
- if status[:errors].present?
.errors
- status[:errors].each do | error |
.error=_"errors.messages.schedule.#{error[:name].to_s}", vars: error[:i18nVars]
= hidden_field_tag :id, workshop.id
= button_tag :deschedule, value: :deschedule_workshop, class: [:delete, :small]
- elsif @can_edit
.title="Block #{time_data[:item][:block] + 1}"
- elsif time_data[:type] != :nil
%td{class: time_data[:type], rowspan: rowspan, colspan: data[:locations].present? ? data[:locations].size : 1}
- case time_data[:type]
- when :meal
- location = EventLocation.where(id: time_data[:item]['location'].to_i).first
- if location.present?
%a.event-detail-link
.details
.title= time_data[:item]['title']
.location= location.title
%template.event-details
%h1.title=time_data[:item]['title']
%p.address
= location.title + _!(': ')
= location_link location
- when :event
- if time_data[:item].event_location.present?
%a.event-detail-link
.details
.title= time_data[:item][:title]
.location= time_data[:item].event_location.title
%template.event-details
%h1.title=time_data[:item][:title]
%p.address
= time_data[:item].event_location.title + _!(': ')
= location_link time_data[:item].event_location
= richtext time_data[:item][:info], 1
- if @entire_page
#workshop-selector
= form_tag administration_update_path(@this_conference.slug, @admin_step), class: 'workshop-dlg', id: 'workshop-table-form' do
%h3 Select a Workshop
#table

46
app/views/conference_administration/_select_guest_table.html.haml

@ -0,0 +1,46 @@
= hidden_field_tag :host, host.id
.host-field
%h4.inline=_'forms.labels.generic.name'
%span.plain-value= host.user.name
.host-field
%h4.inline=_'articles.conference_registration.headings.host.availability'
%span.plain-value= host.housing_data['availability'].present? && host.housing_data['availability'][1].present? ? date_span(host.housing_data['availability'][0].to_date, host.housing_data['availability'][1].to_date) : ''
- if host.housing_data['considerations'].present?
.host-field
%h4.inline=_'articles.conference_registration.headings.host.considerations'
%span.plain-value= (host.housing_data['considerations'].map { | consideration | _"articles.conference_registration.host.considerations.#{consideration}" }).join(', ')
- if sanitize(host.housing_data['notes'], tags: []).present?
.host-field
%h4=_'articles.conference_registration.headings.host.notes'
%blockquote= host.housing_data['notes'].html_safe
%table.guests.admin-edit
%tr
%th.corner
%th=_'forms.labels.generic.city'
%th=_'forms.labels.generic.housing'
%th=_'articles.admin.housing.headings.arrival_departure'
%th=_'articles.conference_registration.headings.companion'
%th=_'forms.labels.generic.food'
%th=_'forms.labels.generic.allergies'
%th=_'forms.labels.generic.other'
- @guests.each do | id, registration |
%tr.selectable{class: get_housing_match(host, registration, space).to_s.gsub('_', '-'), data: {host: host.id, guest: id, space: space}}
%th=registration.user.name
%td=registration.city
%td=registration.housing.present? ? (_"articles.conference_registration.questions.housing.#{registration.housing}") : ''
%td=date_span(registration.arrival.to_date, registration.departure.to_date)
- companion = companion(registration)
%td=companion.present? ? (companion.is_a?(User) ? companion.named_email : (_"articles.conference_registration.terms.registration_status.#{companion}")) : ''
%td=registration.food.present? ? (_"articles.conference_registration.questions.food.#{registration.food}") : ''
%td=registration.allergies
%td
.p=registration.other
.legend
%h4 Legend
%ul
%li.good-match Good Match
%li.bad-match Poor Match
%li.selected-space Also in this space
%li.other-space Also with this host
%li.other-host Already hosted

0
app/views/conferences/admin/_select_workshop_table.html.haml → app/views/conference_administration/_select_workshop_table.html.haml

21
app/views/conference_administration/_stats.html.haml

@ -0,0 +1,21 @@
= columns(medium: 12) do
.details
= data_set(:h3, 'articles.admin.stats.headings.completed_registrations') do
= (@completed_registrations || 0).to_s
= data_set(:h3, 'articles.admin.stats.headings.incomplete_registrations') do
= ((@registration_count - @completed_registrations) || 0).to_s
= data_set(:h3, 'articles.admin.stats.headings.bikes') do
= (@completed_registrations || 0) > 0 ? "#{@bikes} (#{number_to_percentage(@bikes / @completed_registrations.to_f * 100.0)})" : "0"
= data_set(:h3, 'articles.admin.stats.headings.food.meat') do
= (@food[:all] || 0) > 0 ? "#{@food[:meat]} (#{number_to_percentage(@food[:meat] / @food[:all].to_f * 100.0)})" : "0"
= data_set(:h3, 'articles.admin.stats.headings.food.vegetarian') do
= (@food[:all] || 0) > 0 ? "#{@food[:vegetarian]} (#{number_to_percentage(@food[:vegetarian] / @food[:all].to_f * 100.0)})" : "0"
= data_set(:h3, 'articles.admin.stats.headings.food.vegan') do
= (@food[:all] || 0) > 0 ? "#{@food[:vegan]} (#{number_to_percentage(@food[:vegan] / @food[:all].to_f * 100.0)})" : "0"
= data_set(:h3, 'articles.admin.stats.headings.donation_count') do
= (@completed_registrations || 0) > 0 ? "#{@donation_count} (#{number_to_percentage(@donation_count / @completed_registrations.to_f * 100.0)})" : "0"
= data_set(:h3, 'articles.admin.stats.headings.donation_total') do
= "$#{@donations || 0.00}"
.actions
= link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, :stats, :format => :xlsx), class: [:button, :download]
= link_to (_'links.download.Organizations_Excel'), administration_step_path(@this_conference.slug, :organizations, :format => :xlsx), class: [:button, :download, :subdued]

8
app/views/conference_administration/_suggested_amounts.html.haml

@ -0,0 +1,8 @@
= columns(medium: 12) do
= form_tag administration_update_path(@this_conference.slug, @admin_step) do
= fieldset :payment_amounts, label: false do
- payment_amounts = @this_conference.payment_amounts.present? ? @this_conference.payment_amounts : Conference.default_payment_amounts
- for i in 1..5 do
= numberfield "payment_amounts[#{i - 1}]", payment_amounts[i - 1], step: 0.01, min: 0.00, label: false
.actions.right
= button_tag :save, value: :save

19
app/views/conference_administration/_workshop_times.html.haml

@ -0,0 +1,19 @@
= columns(medium: 12) do
.table.workshop-blocks
.table-tr.header
.table-th=_'forms.labels.generic.block_number'
.table-th=_'forms.labels.generic.time'
.table-th=_'forms.labels.generic.length'
.table-th=_'forms.labels.generic.days'
.table-th.form
- @workshop_blocks.each_with_index do | info, block |
- is_new = info['time'].blank?
= form_tag administration_update_path(@this_conference.slug, @admin_step), class: ['table-tr', is_new ? 'new' : 'saved'] do
.table-th.center.big= is_new ? '' : (block + 1)
.table-td=hour_select info['time'], small: true, label: false
.table-td=length_select info['length'], {small: true, label: false}, 0.5, 2
.table-td=checkboxes :days, @block_days, info['days'].map(&:to_i), 'date.day_names', vertical: true, small: true
.table-td.form
= hidden_field_tag :workshop_block, block
= button_tag :delete_block, value: :delete_block, class: [:small, :delete] if block == @workshop_blocks.length - 2
= button_tag (is_new ? :add_block : :update_block), value: :save_block, class: [:small, :add]

27
app/views/conference_administration/administration.html.haml

@ -0,0 +1,27 @@
- body_class 'banner-bottom' unless @this_conference.poster.present?
- content_for :banner do
= render :partial => 'application/header', :locals => { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
%article
= row do
= columns(medium: 12) do
= columns(medium: 12, id: :conferences, class: 'list-view') do
%h2=@this_conference.title
%p=_'articles.admin.paragraphs.administration', :p
%ul.break
- administration_steps.each do | step, actions |
%li
.info
%h3=_"articles.admin.#{step}.heading", :t
.help
%p=_"articles.admin.#{step}.description", :p
.actions.figures
- actions.each do | action |
- action_text = (_"articles.admin.#{step}.headings.#{action}", :t)
.figure
= link_to administration_step_path(@this_conference.slug, action.to_s) do
%header= action_text
.body
= svg "admin/#{action.to_s}", action_text
.description=(_"articles.admin.#{step}.descriptions.#{action}", :s)

38
app/views/conference_administration/administration_step.html.haml

@ -0,0 +1,38 @@
- body_class 'banner-bottom' unless @this_conference.poster.present?
- content_for :banner do
= render :partial => 'application/header', :locals => { page_group: :administration, page_key: 'Administration', image_file: @this_conference.poster_url || 'admin.jpg'}
%article{id: "admin-#{@admin_step}"}
= row do
= columns(medium: 12) do
%h2.floating=(_"articles.admin.#{@admin_group}.headings.#{@admin_step}", :t)
= row do
= columns(medium: 12) do
%nav.sub-nav
%ul
%li=link_to (_'articles.admin.headings.back'), administrate_conference_path(@this_conference.slug)
- administration_steps[@admin_group].each do | step |
%li
- title = (_"articles.admin.#{@admin_group}.headings.#{step}", :t)
- if step == @admin_step.to_sym
= title
- else
= link_to title, administration_step_path(@this_conference.slug, step.to_s)
- if @success_message.present?
= row do
= columns(class: 'info-messages') do
.success-info.info-message=_"success.messages.admin.#{@success_message}", :s
- if @error_message.present?
= row do
= columns(class: 'info-messages') do
.error-info.info-message=_"errors.messages.admin.#{@error_message}", :s
- if @warnings.present?
= row class: 'warnings', tag: :ul do
- @warnings.each do | warning |
= columns tag: :li, class: 'warning-info info-message' do
= warning
= row do
= columns(medium: 12) do
%p=((_"articles.admin.#{@admin_group}.descriptions.#{@admin_step}", :s)) unless @hide_description === true
= row do
= render @admin_step

34
app/views/conferences/_conference.html.haml

@ -0,0 +1,34 @@
- links ||= [ :register ]
- sections ||= [ :info ]
%article
= row(tag: :header) do
= columns(class: 'conference-banner') do
.title
%h1=_!conference.title
.details
%h2.primary=location(conference.city || conference.location) if conference.city_name.present?
- if conference.start_date.present? && conference.end_date.present?
.secondary
= date_span(conference.start_date.to_date, conference.end_date.to_date)
- if conference.poster.present?
%img{src: conference.poster.full.url || image_path('default_poster.jpg'), role: :presentation, alt: (_'images.conference.poster', vars: { conference_title: conference.title })}
= row(class: 'conference-details') do
= columns(medium: 10, push: {medium: 1}) do
%h2=_!conference.title if conference.poster.present?
= richtext conference.info
- if conference.registration_status == :open && sections.include?(:workshops)
- if conference.workshop_schedule_published
- add_inline_script :home_schedule
%h3=_'articles.workshops.headings.Schedule'
= render 'conferences/admin/schedule'
- else
%h3=_'articles.workshops.headings.Proposed_Workshops'
%p=_'articles.workshops.paragraphs.Proposed_Workshops'
= render 'workshops/workshop_previews', :workshops => (conference.workshops.sort { |a, b| a.title.downcase <=> b.title.downcase })
.links
= (link_to (_'forms.actions.generic.register'), register_path(conference.slug), class: [:button, :register]) if links.include?(:register) && conference.registration_status == :open
= (link_to (_'articles.workshops.info.read_more'), conference_path(conference.slug), class: :button) if links.include?(:read_more)
= (link_to (_'forms.actions.generic.administrate'), administrate_conference_path(conference.slug), class: [:button]) if links.include?(:administrate)
= (link_to (_'forms.actions.generic.edit'), edit_conference_path(conference.slug), class: [:button, :subdued]) if links.include?(:edit)

10
app/views/conferences/_header.html.haml

@ -1,10 +1,10 @@
- content_for :banner do
.title
%h1=_!@conference.title
%h1=_!@this_conference.title
.details
%h2.primary=location(@conference.organizations.first.locations.first)
%h2.primary=location(@this_conference.city)
.secondary
= date_span(@conference.start_date.to_date, @conference.end_date.to_date)
%img{src: @conference.poster.full.url || image_path('default_poster.jpg'), role: :presentation, alt: (_'images.conference.poster', vars: { conference_title: @conference.title })}
= date_span(@this_conference.start_date.to_date, @this_conference.end_date.to_date)
%img{src: @this_conference.poster.full.url || image_path('default_poster.jpg'), role: :presentation, alt: (_'images.conference.poster', vars: { conference_title: @this_conference.title })}
- content_for :og_image do
= @conference.poster.full.url || image_path('default_poster.jpg')
= @this_conference.poster.full.url || image_path('default_poster.jpg')

2
app/views/conferences/_page_header.html.haml

@ -1 +1 @@
= render :partial => 'application/header', :locals => {:page_group => :conferences, :page_key => page_key, :image_file => @conference.poster_url}
= render :partial => 'application/header', :locals => {:page_group => :conferences, :page_key => page_key, :image_file => @this_conference.poster_url}

22
app/views/conferences/admin/_broadcast.html.haml

@ -1,22 +0,0 @@
= form_tag administration_update_path(@this_conference.slug, :broadcast) do
- if @broadcast_step == :preview || @broadcast_step == :test
= hidden_field_tag :subject, @subject
= hidden_field_tag :body, @body
= hidden_field_tag :send_to, @send_to
- if @broadcast_step == :preview
%p= _'articles.conference_registration.paragraphs.admin.broadcast.test', vars: { send_to_count: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }
- else
.warning-info.make-room= _'articles.conference_registration.paragraphs.admin.broadcast.preview', vars: { send_to_count: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }
.test-preview
%h4=@subject
= richtext @body, 4
.actions.right
= button_tag :test, value: :test, class: :secondary if @broadcast_step == :preview
= button_with_confirmation :send, (_'modals.admin.broadcast.confirm', vars: { number: "<strong>#{(@send_to_count || 0)}</strong>".html_safe }), value: :send, class: :delete if @broadcast_step == :test
= button_tag :edit, value: :edit
- else
= selectfield :send_to, nil, broadcast_options, full: true
= textfield :subject, @subject, required: true, big: true
= textarea :body, @body, lang: @this_conference.locale, edit_on: :focus
.actions.right
= button_tag :preview, value: :preview

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save