biola_wcms_components 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +74 -0
- data/Rakefile +1 -0
- data/app/assets/images/.gitkeep +0 -0
- data/app/assets/javascripts/biola-wcms-components.js.coffee +15 -0
- data/app/assets/javascripts/components/forms/json_editor.js.coffee +20 -0
- data/app/assets/javascripts/components/forms/person_lookup.js.coffee +29 -0
- data/app/assets/javascripts/components/forms/presentation_data_editor.js.coffee +69 -0
- data/app/assets/javascripts/components/forms/yaml_editor.js.coffee +39 -0
- data/app/assets/javascripts/configuration/file_uploader.js.coffee +55 -0
- data/app/assets/javascripts/configuration/setup_redactor.js.coffee +65 -0
- data/app/assets/stylesheets/_mixins.scss +43 -0
- data/app/assets/stylesheets/_settings.scss +1 -0
- data/app/assets/stylesheets/biola-wcms-components.scss +11 -0
- data/app/assets/stylesheets/components/alerts/_message_list.scss +3 -0
- data/app/assets/stylesheets/components/forms/_person_lookup.scss +72 -0
- data/app/assets/stylesheets/components/forms/_presentation_data_editor.scss +38 -0
- data/app/assets/stylesheets/components/navigation/_site_nav.scss +24 -0
- data/app/helpers/wcms_components/alerts_helper.rb +41 -0
- data/app/helpers/wcms_components/component_helper.rb +9 -0
- data/app/helpers/wcms_components/navigation_helper.rb +32 -0
- data/app/views/wcms_components/alerts/_message_list.html.slim +8 -0
- data/app/views/wcms_components/forms/_json_editor.html.slim +13 -0
- data/app/views/wcms_components/forms/_person_lookup.html.slim +12 -0
- data/app/views/wcms_components/forms/_presentation_data_editor.html.slim +36 -0
- data/app/views/wcms_components/forms/_redactor_editor.html.slim +32 -0
- data/app/views/wcms_components/forms/_text_area.html.slim +13 -0
- data/app/views/wcms_components/forms/_yaml_editor.html.slim +16 -0
- data/app/views/wcms_components/navigation/_page_nav.html.slim +33 -0
- data/app/views/wcms_components/navigation/_site_nav.html.slim +38 -0
- data/app/views/wcms_components/shared/.gitkeep +0 -0
- data/app/views/wcms_components/shared/_embedded_image_uploader.html.slim +6 -0
- data/biola_wcms_components.gemspec +27 -0
- data/config/locales/en.yml +4 -0
- data/lib/biola_wcms_components.rb +22 -0
- data/lib/biola_wcms_components/configuration.rb +9 -0
- data/lib/biola_wcms_components/engine.rb +6 -0
- data/lib/biola_wcms_components/version.rb +3 -0
- data/lib/components/menu_block.rb +130 -0
- data/lib/components/presentation_data_editor.rb +199 -0
- data/vendor/assets/javascripts/handlebars.js +3750 -0
- data/vendor/assets/javascripts/redactor.js +8312 -0
- data/vendor/assets/javascripts/redactor_fullscreen.js +123 -0
- data/vendor/assets/javascripts/typeahead.js +11 -0
- data/vendor/assets/stylesheets/redactor.css +924 -0
- 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,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,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,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'
|