biola_wcms_components 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +74 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/images/.gitkeep +0 -0
  9. data/app/assets/javascripts/biola-wcms-components.js.coffee +15 -0
  10. data/app/assets/javascripts/components/forms/json_editor.js.coffee +20 -0
  11. data/app/assets/javascripts/components/forms/person_lookup.js.coffee +29 -0
  12. data/app/assets/javascripts/components/forms/presentation_data_editor.js.coffee +69 -0
  13. data/app/assets/javascripts/components/forms/yaml_editor.js.coffee +39 -0
  14. data/app/assets/javascripts/configuration/file_uploader.js.coffee +55 -0
  15. data/app/assets/javascripts/configuration/setup_redactor.js.coffee +65 -0
  16. data/app/assets/stylesheets/_mixins.scss +43 -0
  17. data/app/assets/stylesheets/_settings.scss +1 -0
  18. data/app/assets/stylesheets/biola-wcms-components.scss +11 -0
  19. data/app/assets/stylesheets/components/alerts/_message_list.scss +3 -0
  20. data/app/assets/stylesheets/components/forms/_person_lookup.scss +72 -0
  21. data/app/assets/stylesheets/components/forms/_presentation_data_editor.scss +38 -0
  22. data/app/assets/stylesheets/components/navigation/_site_nav.scss +24 -0
  23. data/app/helpers/wcms_components/alerts_helper.rb +41 -0
  24. data/app/helpers/wcms_components/component_helper.rb +9 -0
  25. data/app/helpers/wcms_components/navigation_helper.rb +32 -0
  26. data/app/views/wcms_components/alerts/_message_list.html.slim +8 -0
  27. data/app/views/wcms_components/forms/_json_editor.html.slim +13 -0
  28. data/app/views/wcms_components/forms/_person_lookup.html.slim +12 -0
  29. data/app/views/wcms_components/forms/_presentation_data_editor.html.slim +36 -0
  30. data/app/views/wcms_components/forms/_redactor_editor.html.slim +32 -0
  31. data/app/views/wcms_components/forms/_text_area.html.slim +13 -0
  32. data/app/views/wcms_components/forms/_yaml_editor.html.slim +16 -0
  33. data/app/views/wcms_components/navigation/_page_nav.html.slim +33 -0
  34. data/app/views/wcms_components/navigation/_site_nav.html.slim +38 -0
  35. data/app/views/wcms_components/shared/.gitkeep +0 -0
  36. data/app/views/wcms_components/shared/_embedded_image_uploader.html.slim +6 -0
  37. data/biola_wcms_components.gemspec +27 -0
  38. data/config/locales/en.yml +4 -0
  39. data/lib/biola_wcms_components.rb +22 -0
  40. data/lib/biola_wcms_components/configuration.rb +9 -0
  41. data/lib/biola_wcms_components/engine.rb +6 -0
  42. data/lib/biola_wcms_components/version.rb +3 -0
  43. data/lib/components/menu_block.rb +130 -0
  44. data/lib/components/presentation_data_editor.rb +199 -0
  45. data/vendor/assets/javascripts/handlebars.js +3750 -0
  46. data/vendor/assets/javascripts/redactor.js +8312 -0
  47. data/vendor/assets/javascripts/redactor_fullscreen.js +123 -0
  48. data/vendor/assets/javascripts/typeahead.js +11 -0
  49. data/vendor/assets/stylesheets/redactor.css +924 -0
  50. metadata +176 -0
@@ -0,0 +1 @@
1
+ $color-biola-red: #CC1122;
@@ -0,0 +1,11 @@
1
+ // External files
2
+ @import "../../../vendor/assets/stylesheets/redactor";
3
+
4
+ // Mixins and settings
5
+ @import "./settings";
6
+ @import "./mixins";
7
+
8
+ // Components
9
+ @import "./components/alerts/*";
10
+ @import "./components/forms/*";
11
+ @import "./components/navigation/*";
@@ -0,0 +1,3 @@
1
+ #message_list {
2
+ .alert { margin: 10px 0; }
3
+ }
@@ -0,0 +1,72 @@
1
+ .person-lookup {
2
+ .typeahead, .tt-query, .tt-hint {
3
+ width: 396px;
4
+ height: 34px;
5
+ padding: 8px 12px;
6
+ font-size: 15px;
7
+ line-height: 15px;
8
+ border: 1px solid #ccc;
9
+ -webkit-border-radius: 4px;
10
+ -moz-border-radius: 4px;
11
+ border-radius: 4px;
12
+ outline: none;
13
+ }
14
+
15
+ .tt-query {
16
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
17
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
18
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
19
+ }
20
+
21
+ .tt-hint {
22
+ color: #999
23
+ }
24
+
25
+ .tt-dropdown-menu {
26
+ text-align: left;
27
+ width: 422px;
28
+ margin-top: 12px;
29
+ padding: 8px 0;
30
+ background-color: #fff;
31
+ border: 1px solid #ccc;
32
+ border: 1px solid rgba(0, 0, 0, 0.2);
33
+ -webkit-border-radius: 4px;
34
+ -moz-border-radius: 4px;
35
+ border-radius: 4px;
36
+ -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
37
+ -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
38
+ box-shadow: 0 5px 10px rgba(0,0,0,.2);
39
+ }
40
+
41
+ .tt-suggestion, .tt-empty-message {
42
+ padding: 3px 20px;
43
+ font-size: 16px;
44
+ line-height: 24px;
45
+
46
+ .affiliations {
47
+ color: #999;
48
+ font-size: 12px;
49
+ }
50
+ .image {
51
+ height: 30px;
52
+ width: 26px;
53
+ margin-right: 10px;
54
+ margin-left: -5px;
55
+ display: inline-block;
56
+ vertical-align: middle;
57
+ background-size: cover;
58
+ background-position: center center;
59
+ background-color: #ddd;
60
+ }
61
+ }
62
+
63
+ .tt-suggestion.tt-cursor {
64
+ cursor: pointer;
65
+ color: #fff;
66
+ background-color: #0097cf;
67
+
68
+ .affiliations {
69
+ color: #fff;
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,38 @@
1
+ #presentation_data_editor {
2
+ margin-bottom: 20px;
3
+
4
+ > .nest .nest {
5
+ border-top: 1px solid #ddd;
6
+ border-left: 1px solid #ddd;
7
+ padding: 20px 0 0 20px;
8
+
9
+ h4 {
10
+ margin: 30px 0 5px 0;
11
+ }
12
+ }
13
+
14
+ // Wraps Array name and items
15
+ .array_wrapper {
16
+ margin-bottom: 20px;
17
+ }
18
+
19
+ .array_item {
20
+ border-bottom: 1px solid #ddd;
21
+ padding-bottom: 20px;
22
+ margin-bottom: 20px;
23
+
24
+ // Make the border touch the nested border
25
+ margin-left: -20px;
26
+ padding-left: 20px;
27
+
28
+ // Framework item doesn't get saved
29
+ // it is just there for building out new items
30
+ &.framework {
31
+ display: none;
32
+ }
33
+ }
34
+
35
+ .drop-image-uploader {
36
+ &.dragging { background-color: #deedff; }
37
+ }
38
+ }
@@ -0,0 +1,24 @@
1
+ #wcms_site_navigation {
2
+ background-color: #f3f3f3;
3
+ border-bottom: 1px solid #ddd;
4
+
5
+ a.top-nav-link {
6
+ display: inline-block;
7
+ padding: 10px 0 10px;
8
+ color: inherit;
9
+ }
10
+ .fa-angle-right {
11
+ padding: 0 10px;
12
+ }
13
+
14
+ .custom-dropdown {
15
+ .dropdown-toggle {
16
+ color: inherit;
17
+ }
18
+ .dropdown-menu > .active > a {
19
+ background: none;
20
+ color: black;
21
+ font-weight: bold;
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,41 @@
1
+ module WcmsComponents
2
+ module AlertsHelper
3
+ def all_alerts
4
+ flash_alerts + model_alerts
5
+ end
6
+
7
+ def flash_alerts
8
+ flash.map { |key,val| {type: key, message: val} }
9
+ end
10
+
11
+ def model_alerts(model = nil)
12
+ model ||= instance_variable_get("@#{controller_name.singularize}")
13
+
14
+ return [] if model.nil?
15
+
16
+ model.errors.full_messages.map { |msg| {type: :error, message: msg} }
17
+ end
18
+
19
+ def alert_icon(type)
20
+ case type.to_s.to_sym
21
+ when :error, :alert
22
+ 'fa fa-exclamation-circle'
23
+ when :warn, :warning
24
+ 'fa fa-warning'
25
+ else
26
+ 'fa fa-info-circle'
27
+ end
28
+ end
29
+
30
+ def alert_class(type)
31
+ case type.to_s.to_sym
32
+ when :error, :alert
33
+ 'alert-danger'
34
+ when :warn, :warning
35
+ 'alert-warning' # default yellow
36
+ else
37
+ 'alert-info'
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,9 @@
1
+ module WcmsComponents
2
+ module ComponentHelper
3
+
4
+ def wcms_component(slug, properties={})
5
+ render "wcms_components/#{slug}", properties
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ module WcmsComponents
2
+ module NavigationHelper
3
+
4
+ # Set class on active navigation items
5
+ def nav_link(text, path_helper)
6
+ # The router can't match against a relative root in the path
7
+ # so we need to strip it out with script_name: nil.
8
+ router_path = send(path_helper, script_name: nil)
9
+ real_path = send(path_helper)
10
+
11
+ recognized = ::Rails.application.routes.recognize_path(router_path)
12
+
13
+ if policy(recognized[:controller].classify.constantize).index? # make sure user has permission to index this controller
14
+ if recognized[:controller] == params[:controller] # && recognized[:action] == params[:action]
15
+ content_tag(:li, :class => "descendant active") do
16
+ link_to( text, real_path)
17
+ end
18
+ else
19
+ content_tag(:li, :class => "descendant") do
20
+ link_to( text, real_path)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ # Gets used by the side menu / page navigation
27
+ def menu_block(html_options = {}, &block)
28
+ MenuBlock.new(self, html_options).render(&block)
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,8 @@
1
+ .container
2
+ - unless (alerts = all_alerts).empty?
3
+ #message_list
4
+ - alerts.each do |msg|
5
+ .alert class=alert_class(msg[:type]) data-type=msg[:type]
6
+ a.close data-dismiss="alert" href="#" ×
7
+ i> class=alert_icon(msg[:type])
8
+ = msg[:message]
@@ -0,0 +1,13 @@
1
+ ruby:
2
+ form ||= nil
3
+ attribute ||= nil
4
+ html_class ||= 'form-control json_editor'
5
+ value ||= nil
6
+ embedded_image_url ||= nil # should be the post url for creating new embedded images
7
+
8
+
9
+ = wcms_component("shared/embedded_image_uploader", embedded_image_url: embedded_image_url)
10
+
11
+ .ace_json_editor
12
+ = wcms_component("forms/text_area", {form: form, attribute: attribute, html_class: html_class, value: value})
13
+
@@ -0,0 +1,12 @@
1
+ ruby:
2
+ lookup_url ||= nil
3
+
4
+ - if lookup_url
5
+ .person-lookup data-lookup-url=lookup_url
6
+ = hidden_field_tag :person_id, '', class: 'hidden-person-id'
7
+ = text_field_tag :person_name, '', placeholder: 'First or last name', required: true, class: 'form-control typeahead'
8
+
9
+ - else
10
+ p
11
+ ' Please specify
12
+ code = ":lookup_url"
@@ -0,0 +1,36 @@
1
+ / Example:
2
+ / = wcms_component "forms/presentation_data_editor",
3
+ / schema: @generic_object.presentation_data_template.schema,
4
+ / data: @generic_object.presentation_data,
5
+ / form: f,
6
+ / embedded_image_url: create_embedded_images_url
7
+ /
8
+
9
+ ruby:
10
+ schema ||= []
11
+ presentation_data ||= {}
12
+ form ||= nil
13
+ embedded_image_url ||= nil # should be the post url for creating new embedded images
14
+
15
+ = wcms_component "shared/embedded_image_uploader",
16
+ embedded_image_url: embedded_image_url
17
+
18
+
19
+ / Link to toggle between simple and advanced editors
20
+ - if current_user.try(:admin?)
21
+ - if params[:edit_raw_data] == 'true'
22
+ = link_to('Simple Editor', params.merge(edit_raw_data: nil), class: 'pull-right')
23
+ - else
24
+ = link_to('Edit Raw Data', params.merge(edit_raw_data: true), class: 'pull-right')
25
+ .clearfix
26
+
27
+
28
+ - if params[:edit_raw_data] == 'true' && current_user.try(:admin?)
29
+ / Render JSON editor
30
+ = wcms_component 'forms/json_editor',
31
+ form: form,
32
+ attribute: :presentation_data_json
33
+
34
+ - else
35
+ / Render HTML for presentation data editor
36
+ = PresentationDataEditor.new(self, presentation_data, schema, form).render
@@ -0,0 +1,32 @@
1
+ / Example:
2
+ / = wcms_component("forms/redactor_editor", {form: f,
3
+ / attribute: :body,
4
+ / add_buttons: ['link'],
5
+ / })
6
+
7
+
8
+ ruby:
9
+ # Default Parameters
10
+ form ||= nil
11
+ attribute ||= nil # attribute name that the editor should be attached to
12
+ add_class ||= "" # string of additional classes that get appended to class
13
+ input_class ||= "form-control redactor #{add_class}"
14
+ value ||= nil # only used if form is nil
15
+
16
+ # Configure buttons
17
+ buttons ||= BiolaWcmsComponents.config.default_redactor_buttons
18
+ add_buttons ||= [] # adds to defaults
19
+ remove_buttons ||= [] # removes from default
20
+ buttons = Array(buttons) + Array(add_buttons) - Array(remove_buttons)
21
+ buttons << 'html_options' if current_user.try(:admin?)
22
+ buttons << 'fullscreen'
23
+
24
+ # Turn buttons into a string and make sure there are no duplicates
25
+ buttons = buttons.uniq.join(' ')
26
+
27
+
28
+
29
+ - if form
30
+ = form.text_area attribute, class: input_class, 'data-buttons' => buttons
31
+ - else
32
+ = text_area_tag attribute, value, class: input_class, 'data-buttons' => buttons
@@ -0,0 +1,13 @@
1
+ ruby:
2
+ form ||= nil
3
+ attribute ||= nil
4
+ html_class ||= 'form-control'
5
+ value ||= nil
6
+
7
+ html_options = {class: html_class}
8
+ html_options[:value] = value if value.present? # you don't want to pass value as an option if it is nil
9
+
10
+ - if form
11
+ = form.text_area attribute, html_options
12
+ - else
13
+ = text_area_tag attribute, value, html_options
@@ -0,0 +1,16 @@
1
+ ruby:
2
+ form ||= nil
3
+ attribute ||= nil
4
+ html_class ||= 'form-control'
5
+ value ||= nil
6
+ embedded_image_url ||= nil # should be the post url for creating new embedded images
7
+
8
+ # Set default value
9
+ # We have to do it this way in case value is an empty string (as opposed to nil).
10
+ value = value.presence || "---\n# YAML data goes here...\n"
11
+
12
+
13
+ = wcms_component("shared/embedded_image_uploader", embedded_image_url: embedded_image_url)
14
+
15
+ .ace_yaml_editor
16
+ = wcms_component("forms/text_area", {form: form, attribute: attribute, html_class: html_class, value: value})
@@ -0,0 +1,33 @@
1
+ / I'm going to wait to implement this one fully...
2
+ / The problem is going to be supporting submenus like on profile publisher
3
+ /
4
+ / Example:
5
+ / = wcms_component('navigation/page_menu', { menu_items: [ \
6
+ / {body: 'Profile', url: edit_academic_program_path(@academic_program, page: 'profile'), default: true },
7
+ / {body: 'Relationships', url: edit_academic_program_path(@academic_program, page: 'relationships') },
8
+ / {body: 'Concentrations', url: edit_academic_program_path(@academic_program, page: 'concentrations') },
9
+ / {body: 'Degree Requirements', url: edit_academic_program_path(@academic_program, page: 'degree_requirements') },
10
+ / {body: 'Requirement Sections', url: edit_academic_program_path(@academic_program, page: 'requirement_sections') },
11
+ / {body: 'Outcomes', url: edit_academic_program_path(@academic_program, page: 'outcomes') },
12
+ / {body: 'Attachments', url: edit_academic_program_path(@academic_program, page: 'attachments') },
13
+ / {body: 'Banner', url: edit_academic_program_path(@academic_program, page: 'banner') },
14
+ / {body: 'Presentation Data', url: edit_academic_program_path(@academic_program, page: 'presentation_data') },
15
+ / {body: 'History', url: edit_academic_program_path(@academic_program, page: 'activity_logs'), visible: policy(@academic_program).can_manage?(:activity_logs) },
16
+ / ]})
17
+ /
18
+
19
+
20
+
21
+ /---------------
22
+ / ON HOLD...
23
+ /---------------
24
+ / ruby:
25
+ / menu_items ||= []
26
+
27
+ / = menu_block(class: 'list-group-item') do |menu|
28
+ / - menu_items.each do |item|
29
+ / / It needs to be explicitly set to false to be hidden
30
+ / - unless item.visible == false
31
+ / = menu.add_item(item[:body], default: item[:default]) { item[:url] }
32
+
33
+
@@ -0,0 +1,38 @@
1
+ / Parameters
2
+ / menu: Array of hashes. This is what goes in the dropdown menu
3
+ / body: This is the link text
4
+ / url: This is where the link will go. Gets processed by url_for()
5
+ / crumbs: (optional) Array of hashes. These are the crumbs after the main menu
6
+ / add_crumbs: (optional) Array of hashes. These get pushed onto the default crumbs
7
+ /
8
+ / Example:
9
+ / = wcms_component('navigation/site_nav', { menu: [ \
10
+ / {body: 'Academic Programs', url: :academic_programs_path},
11
+ / {body: 'Schools', url: :schools_path},
12
+ / {body: 'ULOs', url: :university_learning_outcomes_path},
13
+ / ]})
14
+ /
15
+
16
+ ruby:
17
+ menu ||= []
18
+ crumbs ||= [{
19
+ body: controller_name.titleize,
20
+ url: {controller: controller_name, action: :index}
21
+ }]
22
+ crumbs += Array(add_crumbs) if defined?(add_crumbs)
23
+
24
+
25
+ #wcms_site_navigation
26
+ .container
27
+ - if menu.present?
28
+ .dropdown.custom-dropdown
29
+ a.dropdown-toggle href='#' data-toggle='dropdown' role='button' Menu
30
+ ul.dropdown-menu
31
+ - menu.each do |link|
32
+ = nav_link(link[:body], link[:url])
33
+ - else
34
+ = link_to 'Home', root_url, class: 'top-nav-link'
35
+
36
+ - crumbs.each do |crumb|
37
+ i class='fa fa-angle-right'
38
+ = link_to crumb[:body], crumb[:url], class: 'top-nav-link'