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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3564d479c782c49da3714d46d516fbc535e40cfa
4
+ data.tar.gz: 19904bda0bb747bfd063e87683cdb12391ec7de3
5
+ SHA512:
6
+ metadata.gz: bea91bf31935f7321f8a5e2aadfa5e7eceef27781eb5abbc70bbb346e5dffafc03adc46a80c2d39932e93126222e495f1a70e3e54d7003e25d2068ae65c6c287
7
+ data.tar.gz: 3157ae4e247df688200788bfac820cec812a1199c5fbb43217c24e82893902b24bac5e94dba651d34369331fd93b02008e7bb77778b8fb8257b8594477203f17
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ .rspec
4
+ Gemfile.lock
@@ -0,0 +1 @@
1
+ 2.1.4
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in biola_wcms_components.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Ryan Hall
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ # Biola WCMS Components
2
+
3
+ This provides reusable UX components for our differnet WCMS projects
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'biola_wcms_components'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install biola_wcms_components
18
+
19
+ #### Dependencies
20
+
21
+ * ace-rails-ap
22
+ * coffee-rails
23
+ * sass-rails
24
+ * slim
25
+ * rails (this is not an explicit dependency but I haven't tested it using anything else)
26
+
27
+ ## Usage
28
+
29
+ ### Rails > 3.1
30
+
31
+ Include the following in `application.css.scss`.
32
+
33
+ @import "biola-wcms-components";
34
+
35
+ Include the following in `application.js.coffee`.
36
+
37
+ #= require biola-wcms-components
38
+
39
+
40
+ ### Components
41
+
42
+ In your view file, you will render `wcms_component("path/to/component", options)`
43
+
44
+ Example:
45
+
46
+ = wcms_component "forms/presentation_data_editor",
47
+ schema: @generic_object.presentation_data_template.schema,
48
+ data: @generic_object.presentation_data,
49
+ form: f,
50
+ embedded_image_url: create_embedded_images_url
51
+
52
+ Currently, look in `app/views/wcms_components` for available components.
53
+
54
+
55
+ #### Other requirements
56
+
57
+ * `current_user` - should be defined an ApplicationController. Should return user when logged in
58
+
59
+ #### Configuration
60
+
61
+ Create a new file called `/config/initializers/biola_wcms_components.rb`
62
+
63
+ BiolaWcmsComponents.configure do |config|
64
+ config.default_redactor_buttons = ['bold', 'italic', 'orderedlist', 'unorderedlist']
65
+ end
66
+
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
File without changes
@@ -0,0 +1,15 @@
1
+ #= require ace/ace
2
+ #= require ace/mode-yaml
3
+ #= require ace/mode-json
4
+ #= require ace/worker-json
5
+ #
6
+ # Handlebars and typeahead are needed for the person-lookup component
7
+ #= require handlebars
8
+ #= require typeahead
9
+ #
10
+ #= require redactor
11
+ #= require redactor_fullscreen
12
+ #
13
+ #= require_tree ./configuration
14
+ #= require_tree ./components
15
+ #= require_self
@@ -0,0 +1,20 @@
1
+ $(document).ready ->
2
+ $('.ace_json_editor').each ->
3
+ editor_area = document.createElement('div')
4
+ this.appendChild(editor_area)
5
+
6
+ # Initialize Ace Editor
7
+ editor = ace.edit(editor_area)
8
+ editor.getSession().setMode("ace/mode/json")
9
+ editor.getSession().setTabSize(2)
10
+ editor.getSession().setUseWrapMode(true);
11
+ editor.setPrintMarginColumn(800)
12
+ editor.setOptions({
13
+ minLines: 8,
14
+ maxLines: Infinity
15
+ });
16
+
17
+ textarea = $(this).children('textarea').hide()
18
+ editor.getSession().setValue textarea.val()
19
+ editor.getSession().on "change", ->
20
+ textarea.val editor.getSession().getValue()
@@ -0,0 +1,29 @@
1
+ $(document).ready ->
2
+ if $('.person-lookup').length > 0
3
+ people_search_url = $('.person-lookup').first().data('lookup-url')
4
+
5
+ peopleSearch = new Bloodhound(
6
+ datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value')
7
+ queryTokenizer: Bloodhound.tokenizers.whitespace
8
+ # The prefetch url returns a list of all the faculty
9
+ prefetch: people_search_url
10
+ remote: people_search_url + '?q=%QUERY'
11
+ )
12
+
13
+ peopleSearch.initialize()
14
+ $('.person-lookup .typeahead').typeahead null,
15
+ name: 'people-search'
16
+ displayKey: (person) ->
17
+ person.name + " <#{person.email || person.id}>"
18
+ highlight: true
19
+ source: peopleSearch.ttAdapter()
20
+ templates:
21
+ empty: '<div class="tt-empty-message">No one found with that name</div>'
22
+ suggestion: Handlebars.compile(
23
+ '<span class="image" style="background-image: url({{image}})" ></span>' +
24
+ '<span class="name">{{name}}</span> <span class="affiliations">{{affiliations}}</span>'
25
+ )
26
+
27
+ # We need to submit the ID through a hidden input for improved lookup.
28
+ $('.person-lookup .typeahead').on "typeahead:selected typeahead:autocompleted", (e,datum) ->
29
+ $('.person-lookup .hidden-person-id').val datum.id
@@ -0,0 +1,69 @@
1
+ $(document).ready ->
2
+ if $('#presentation_data_editor').length > 0
3
+
4
+ # Disable all framework fields, otherwise they will save on submit
5
+ $('.array_wrapper .framework').find('input, textarea').each ->
6
+ this.disabled = true
7
+
8
+ # Delete an array item when you click the delete button
9
+ $('.array_wrapper').on 'click', '.delete_array_item', ->
10
+ $(this).parents('.array_item').remove()
11
+ false
12
+
13
+ # Add an new array item from the last array_item
14
+ $('.array_wrapper .add_array_item').click ->
15
+ last_item = $(this).siblings('.array_item').last()
16
+ framework = $(this).siblings('.array_item.framework').last()
17
+ new_item = framework.clone()
18
+ new_item.removeClass("framework")
19
+
20
+ # Get array number for last item
21
+ last_number = last_item.find('input, textarea').first().attr('id').match(/\d+/)
22
+ new_number = +last_number[0] + 1
23
+
24
+ # Loop through each element and enable it.
25
+ # They have to be disabled in the framework form so they don't get submitted
26
+ new_item.find('input, textarea').each ->
27
+ this.id = this.id.replace(/\d+/, new_number)
28
+ this.disabled = false
29
+ this.value = ""
30
+
31
+ # Append to DOM after last item
32
+ last_item.after(new_item)
33
+
34
+ # Setup redactor for new item
35
+ # NOTE: This is the reason I am copying the 'framework' item above,
36
+ # because redactor is already setup for the other items.
37
+ # I explicitly exclude redactor setup from items nested under 'framework'
38
+ setupRedactorEditorsUnder(new_item)
39
+
40
+ false
41
+
42
+
43
+
44
+
45
+
46
+ ##############################
47
+ # Setup drag-drop image upload
48
+ ##############################
49
+ uploadImage = (file, input) ->
50
+ fileUploader.sendFileToServer file, 'embedded_image', ((url) ->
51
+ input.value = url
52
+ ), ->
53
+ alert('There was a problem uploading the image')
54
+
55
+ $('#presentation_data_editor').on 'dragover', 'input.drop-image-uploader', (e) ->
56
+ event.preventDefault()
57
+ event.stopPropagation()
58
+ $(this).addClass('dragging')
59
+
60
+ $('#presentation_data_editor').on 'dragleave', 'input.drop-image-uploader', (e) ->
61
+ event.preventDefault()
62
+ event.stopPropagation()
63
+ $(this).removeClass('dragging')
64
+
65
+ $('#presentation_data_editor').on 'drop', 'input.drop-image-uploader', (e) ->
66
+ event.preventDefault()
67
+ event.stopPropagation()
68
+ uploadImage(e.originalEvent.dataTransfer.files[0], this)
69
+ $(this).removeClass('dragging')
@@ -0,0 +1,39 @@
1
+ # This is depricated. We will keep this around until we have moved everything over to the new
2
+ # plain data form editor.
3
+
4
+ $(document).ready ->
5
+ $('.ace_yaml_editor').each ->
6
+ editor_area = document.createElement('div')
7
+ this.appendChild(editor_area)
8
+
9
+ # Initialize Ace Editor
10
+ editor = ace.edit(editor_area)
11
+ editor.getSession().setMode("ace/mode/yaml")
12
+ editor.getSession().setTabSize(2)
13
+ editor.setPrintMarginColumn(800)
14
+ editor.setOptions({
15
+ minLines: 8,
16
+ maxLines: Infinity
17
+ });
18
+
19
+ textarea = $(this).children('textarea').hide()
20
+ editor.getSession().setValue textarea.val()
21
+ editor.getSession().on "change", ->
22
+ textarea.val editor.getSession().getValue()
23
+
24
+
25
+ # Setup drag-drop image upload
26
+ editor.container.addEventListener 'dragover', (e) =>
27
+ e.preventDefault()
28
+ e.stopPropagation()
29
+
30
+ editor.container.addEventListener 'dragleave', (e) =>
31
+ e.preventDefault()
32
+ e.stopPropagation()
33
+
34
+ editor.container.addEventListener 'drop', (e) =>
35
+ e.preventDefault()
36
+ e.stopPropagation()
37
+ fileUploader.sendFileToServer e.dataTransfer.files[0], 'embedded_image', (url) ->
38
+ editor.insert('"' + url + '"')
39
+
@@ -0,0 +1,55 @@
1
+ # In order to use you must first set up an uploader
2
+ # Example:
3
+ # fileUploader.addUploader('embedded_image', "http://api.example.com/uploader");
4
+ #
5
+ # Then you can send a file to that uploader whenever you are ready.
6
+ # Example:
7
+ # fileUploader.sendFileToServer file, 'embedded_image', ((url) ->
8
+ # alert 'success!'
9
+ # ), ->
10
+ # alert 'error :('
11
+ #
12
+
13
+
14
+ window.fileUploader ||= {
15
+ uploaders: {}
16
+ }
17
+
18
+ fileUploader.addUploader = (key, url) ->
19
+ fileUploader.uploaders[key] = url
20
+
21
+ fileUploader.sendFileToServer = (file, urlKey, successCallback, errorCallback) ->
22
+ if fileUploader.uploaders[urlKey]
23
+ form_data = new FormData()
24
+ form_data.append('file', file)
25
+ form_data.append('authenticity_token', $('[name=csrf-token').attr('content'))
26
+
27
+ xhr = new XMLHttpRequest()
28
+ xhr.open "POST", fileUploader.uploaders[urlKey]
29
+
30
+ # complete
31
+ xhr.onreadystatechange = $.proxy(->
32
+ if xhr.readyState is 4
33
+ data = xhr.responseText
34
+ data = data.replace(/^\[/, "")
35
+ data = data.replace(/\]$/, "")
36
+ json = undefined
37
+ try
38
+ json = ((if typeof data is "string" then $.parseJSON(data) else data))
39
+ catch err
40
+ json = error: true
41
+
42
+ if json.error
43
+ if errorCallback
44
+ errorCallback()
45
+ else
46
+ alert('There was a problem uploading the file')
47
+ else
48
+ successCallback(json.filelink)
49
+ return
50
+ , this)
51
+ xhr.send form_data
52
+
53
+ else
54
+ alert('Uploader is not configured.')
55
+
@@ -0,0 +1,65 @@
1
+ setupRedactor = (obj) ->
2
+ # Default Options
3
+ options =
4
+ minHeight: 200
5
+ allowedTags: ['p', 'br']
6
+ buttons: []
7
+
8
+ # Add any custom data attributes to the default options
9
+ if obj.data('linkable') # in case you want to support links without explicitly giving a link button.
10
+ options.allowedTags = $.merge(options.allowedTags, 'a')
11
+ if data = obj.data('buttons')
12
+ buttons = data.split(' ')
13
+ options.buttons = $.merge(options.buttons, buttons)
14
+ options.allowedTags = $.merge(options.allowedTags, buttonsToTags(buttons))
15
+ if tuned_data = obj.data('formatting')
16
+ formatting = tuned_data.split (' ')
17
+ options.formatting = tuned_data.split (' ')
18
+ if options.allowedTags.indexOf('a') >= 0
19
+ options.convertLinks = true;
20
+ if options.buttons.indexOf('fullscreen') >= 0
21
+ options.plugins = ['fullscreen']
22
+
23
+ # Uniq all arrays
24
+ options.buttons = $.unique(options.buttons)
25
+ if formatting
26
+ options.formatting = $.unique(options.formatting)
27
+ options.allowedTags = $.unique(options.allowedTags)
28
+
29
+ # Initialize redactor
30
+ obj.redactor(options)
31
+
32
+
33
+ button_to_tag_mapping =
34
+ bold: ['b', 'strong']
35
+ italic: ['i', 'em']
36
+ link: ['a']
37
+ orderedlist: ['ol', 'li']
38
+ table: ['table', 'tr', 'tbody', 'td']
39
+ unorderedlist: ['ul', 'li']
40
+
41
+ buttonsToTags = (buttons) ->
42
+ tags = []
43
+ $.each buttons, (index, value) ->
44
+ if mapping = button_to_tag_mapping[value]
45
+ tags = $.merge(tags, mapping)
46
+ tags
47
+
48
+
49
+ window.setupRedactorEditorsUnder = (obj) ->
50
+ # Initialize redactor on items with the class 'redactor'
51
+ $(obj).find("textarea.redactor:enabled").each (i) ->
52
+ # Don't setup redactor if the textarea inherits from a "framework" item.
53
+ # framework items are hidden and are used to add new items to a form array.
54
+ # If it inherits from .redactor-box that means it has already been initialized.
55
+ unless $(this).parents('.framework, .redactor-box').length > 0
56
+ setupRedactor($(this))
57
+
58
+
59
+ $(document).ready ->
60
+ # Run on startup
61
+ setupRedactorEditorsUnder('body')
62
+
63
+ # Run when modals open
64
+ $(".modal").on "shown.bs.modal", (e) ->
65
+ setupRedactorEditorsUnder('.modal')
@@ -0,0 +1,43 @@
1
+ //===============================================
2
+ // Toggle-able media queries and old IE helper
3
+ // See: http://jakearchibald.github.io/sass-ie/
4
+ //===============================================
5
+ $fix-mqs: false !default;
6
+ $old-ie: false !default;
7
+ $max-width-extreme:9999px;
8
+
9
+ @mixin respond($min-width:0, $max-width:$max-width-extreme, $orientation:null) {
10
+ // If we're outputting for a fixed media query set...
11
+ @if $fix-mqs {
12
+ // ...and if we should apply these rules...
13
+ @if $fix-mqs >= $min-width and $fix-mqs <= $max-width {
14
+ // ...output the content the user gave us.
15
+ @content;
16
+ }
17
+ }
18
+ @else {
19
+ // Otherwise, output it using a regular media query
20
+ $query:'screen';
21
+
22
+ @if $min-width > 0 {
23
+ $query:$query + " and (min-width:#{$min-width})";
24
+ }
25
+ @if $max-width < $max-width-extreme {
26
+ $query:$query + " and (max-width:#{$max-width})";
27
+ }
28
+ @if $orientation {
29
+ $query:$query + " and (orientation:#{$orientation})";
30
+ }
31
+
32
+ @media #{$query} {
33
+ @content;
34
+ }
35
+ }
36
+ }
37
+
38
+ @mixin old-ie {
39
+ // Only use this content if we're dealing with old IE
40
+ @if $old-ie {
41
+ @content;
42
+ }
43
+ }