sir-trevor-rails 0.1.3

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.
Files changed (50) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +101 -0
  4. data/MIT-LICENCE +20 -0
  5. data/README.md +120 -0
  6. data/Rakefile +10 -0
  7. data/app/assets/images/sir-trevor/icons/block_editor_blockquote.png +0 -0
  8. data/app/assets/images/sir-trevor/icons/block_editor_embed.png +0 -0
  9. data/app/assets/images/sir-trevor/icons/block_editor_image.png +0 -0
  10. data/app/assets/images/sir-trevor/icons/block_editor_list.png +0 -0
  11. data/app/assets/images/sir-trevor/icons/block_editor_text.png +0 -0
  12. data/app/assets/images/sir-trevor/icons/block_editor_tweet.png +0 -0
  13. data/app/assets/images/sir-trevor/icons/block_editor_video.png +0 -0
  14. data/app/assets/images/sir-trevor/icons/close.gif +0 -0
  15. data/app/assets/images/sir-trevor/icons/handle.gif +0 -0
  16. data/app/assets/images/sir-trevor/icons/new_image.png +0 -0
  17. data/app/assets/images/sir-trevor/icons/new_tweet.png +0 -0
  18. data/app/assets/images/sir-trevor/icons/new_video.png +0 -0
  19. data/app/assets/images/sir-trevor/icons/quote.png +0 -0
  20. data/app/assets/images/sir-trevor/placeholders/placeholder.jpg +0 -0
  21. data/app/assets/images/sir-trevor/placeholders/post_placeholder.jpg +0 -0
  22. data/app/assets/images/sir-trevor/placeholders/thumbnail_placeholder.jpg +0 -0
  23. data/app/assets/javascript/sir-trevor.js +2 -0
  24. data/app/assets/javascript/sir-trevor/libs/underscore.js +32 -0
  25. data/app/assets/javascript/sir-trevor/sir-trevor.js +2363 -0
  26. data/app/assets/stylesheets/sir-trevor.css +4 -0
  27. data/app/assets/stylesheets/sir-trevor/icons.css.erb +47 -0
  28. data/app/assets/stylesheets/sir-trevor/sir-trevor.css +551 -0
  29. data/app/views/sir-trevor/blocks/_gallery_block.html.erb +6 -0
  30. data/app/views/sir-trevor/blocks/_image_block.html.erb +3 -0
  31. data/app/views/sir-trevor/blocks/_quote_block.html.erb +4 -0
  32. data/app/views/sir-trevor/blocks/_text_block.html.erb +3 -0
  33. data/app/views/sir-trevor/blocks/_tweet_block.html.erb +6 -0
  34. data/app/views/sir-trevor/blocks/_ul_block.html.erb +3 -0
  35. data/app/views/sir-trevor/blocks/_video_block.html.erb +7 -0
  36. data/config/initializers/validators.rb +10 -0
  37. data/lib/generators/sir_trevor/block/block_generator.rb +37 -0
  38. data/lib/generators/sir_trevor/block/templates/_block.css.erb +7 -0
  39. data/lib/generators/sir_trevor/block/templates/_block.html.erb +3 -0
  40. data/lib/generators/sir_trevor/block/templates/_block.js +122 -0
  41. data/lib/generators/sir_trevor/block/templates/_block.png +0 -0
  42. data/lib/generators/sir_trevor/views/views_generator.rb +17 -0
  43. data/lib/sir-trevor-rails.rb +19 -0
  44. data/lib/sir-trevor/engine.rb +29 -0
  45. data/lib/sir-trevor/helpers/form_builder.rb +11 -0
  46. data/lib/sir-trevor/helpers/form_helper.rb +29 -0
  47. data/lib/sir-trevor/helpers/view_helper.rb +78 -0
  48. data/lib/sir-trevor/version.rb +3 -0
  49. data/sir-trevor-rails.gemspec +29 -0
  50. metadata +174 -0
@@ -0,0 +1,6 @@
1
+ <% # Remember, a gallery is just an array of images ;-) %>
2
+ <div class="content-block gallery-block">
3
+ <% block.each do |image| %>
4
+ <%= render(:partial => "sir-trevor/blocks/image_block", :locals => {:block => image['data'], :image_type => image_type, :protocol => request.protocol}, :formats => formats) if image.has_key?("data") && image['type'] == "image" %>
5
+ <% end %>
6
+ </div>
@@ -0,0 +1,3 @@
1
+ <figure class="content-block image-block">
2
+ <%= sir_trevor_image_tag(block, image_type) %>
3
+ </figure>
@@ -0,0 +1,4 @@
1
+ <div class="content-block quote-block">
2
+ <%= sir_trevor_markdown block["text"] %>
3
+ <%= "<cite class=\"quote\">&ndash; #{block["cite"]}</cite>".html_safe unless block["cite"].nil? %>
4
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="content-block text-block">
2
+ <%= sir_trevor_markdown block["text"] %>
3
+ </div>
@@ -0,0 +1,6 @@
1
+ <div class="content-block tweet-block">
2
+ <%= link_to image_tag("http://twitter.com/api/users/profile_image/#{ block['user']['screen_name'] }?size=bigger", :class => 'img'), "http://twitter.com/#{ block['user']['screen_name'] }" %>
3
+ <p><%= auto_link(block['text']).html_safe %></p>
4
+ <cite>From <%= link_to "@#{ block['user']['screen_name'] }", "http://twitter.com/#{ block['user']['screen_name'] }" %> on Twitter:</cite>
5
+ <time datetime="<%= block['created_at'] %>">(<%= link_to Time.parse(block['created_at']), "http://twitter.com/#{block['user']['screen_name']}/status/#{block['id_str']}" %>)</time>
6
+ </div>
@@ -0,0 +1,3 @@
1
+ <div class="content-block ul-block">
2
+ <%= sir_trevor_markdown block["text"] %>
3
+ </div>
@@ -0,0 +1,7 @@
1
+ <div class="content-block video-block">
2
+ <% if block['source'] == 'vimeo' %>
3
+ <iframe src="<%= protocol %>player.vimeo.com/video/<%= block['remote_id'] %>?title=1&amp;byline=1&amp;portrait=1&amp;autoplay=0" width="600" height="400" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>
4
+ <% elsif block['source'] == 'youtube' %>
5
+ <iframe width="600" height="400" src="<%= protocol %>www.youtube.com/embed/<%= block['remote_id'] %>" frameborder="0" allowfullscreen></iframe>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1,10 @@
1
+ class IsJsonValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ @json = JSON.parse(value)
4
+ record.errors.add(attribute, "is empty") if @json.empty?
5
+ rescue TypeError => e
6
+ record.errors.add(attribute, "is not valid JSON: #{e.message}")
7
+ rescue JSON::JSONError => e
8
+ record.errors.add(attribute, "is not valid JSON: #{e.message}")
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ require 'rails/generators'
2
+
3
+ module SirTrevor
4
+ module Generators
5
+ class BlockGenerator < Rails::Generators::NamedBase
6
+
7
+ def self.source_root
8
+ @source_root ||= File.join(File.dirname(__FILE__), 'templates')
9
+ end
10
+
11
+ def create_block
12
+
13
+ # Copy our PNG
14
+ copy_file "_block.png", "app/assets/images/sir-trevor/blocks/block_editor_#{name}.png"
15
+
16
+ # Copy the JS
17
+ copy_file "_block.js", "app/assets/javascripts/sir-trevor/blocks/#{name}.js"
18
+
19
+ gsub_file "app/assets/javascripts/sir-trevor/blocks/#{name}.js", /SirTrevor\.Blocks\.Name/, "SirTrevor.Blocks.#{name.capitalize}"
20
+ gsub_file "app/assets/javascripts/sir-trevor/blocks/#{name}.js", /title: ""/, "title: '#{name.capitalize}'"
21
+ gsub_file "app/assets/javascripts/sir-trevor/blocks/#{name}.js", /className: ""/, "className: '#{name.downcase}'"
22
+
23
+ # Copy the CSS
24
+ copy_file "_block.css.erb", "app/assets/stylesheets/sir-trevor/blocks/#{name}_block.css.erb"
25
+ gsub_file "app/assets/stylesheets/sir-trevor/blocks/#{name}_block.css.erb", /_block\.png/, "#{name}_block.png"
26
+ gsub_file "app/assets/stylesheets/sir-trevor/blocks/#{name}_block.css.erb", /a.new-/, "a.new-#{name}"
27
+ gsub_file "app/assets/stylesheets/sir-trevor/blocks/#{name}_block.css.erb", /\.-block/, ".#{name}-block"
28
+
29
+ # Copy the HTML
30
+ copy_file "_block.html.erb", "app/views/sir-trevor/blocks/_#{name}_block.html.erb"
31
+ gsub_file "app/views/sir-trevor/blocks/_#{name}_block.html.erb", /\s(-block)/, " #{name}-block"
32
+
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ .sir-trevor .sir-trevor-marker .buttons a.new- {
2
+ background-image: url(<%= asset_path 'sir-trevor/icons/block_editor_.png' %>);
3
+ }
4
+
5
+ .sir-trevor .sir-trevor-block .-block {
6
+ /* Your block styles */
7
+ }
@@ -0,0 +1,3 @@
1
+ <div class="content-block -block">
2
+ <%= block.inspect %>
3
+ </div>
@@ -0,0 +1,122 @@
1
+ SirTrevor.Blocks.Name = SirTrevor.Block.extend({
2
+
3
+ // String; the title displayed in the toolbar
4
+ title: "",
5
+
6
+ // String; the class name of the block type
7
+ className: "",
8
+
9
+ // Integer; the overall number of blocks of this type that can be added
10
+ limit: 0,
11
+
12
+ // Boolean; show this blockType of the toolbar
13
+ toolbarEnabled: true,
14
+
15
+ // Booleam; set this block up for drag and drop
16
+ // dropEnabled: true,
17
+
18
+ // String or Function; The HTML for the inner portion of the editor block
19
+ // In this example, the editorHTML is an editable input div (like we use for a TextBlock)
20
+ editorHTML: "<div></div>",
21
+ // editorHTML must return a string (if it's a function)
22
+ // editorHTML: function() {},
23
+
24
+ // String; The HTML for the dropzone
25
+ // Not required unless dropEnabled is true
26
+ dropzoneHTML: "<div class='dropzone'><p>Drop content here yo!</p></div>",
27
+
28
+ // Element shorthands
29
+ // --
30
+ // this.$el
31
+ // this.el
32
+ // this.$editor
33
+ // this.$dropzone
34
+ // this.$() (same as this.$el.find(''))
35
+ // this.$$() (same as this.$editor.find(''))
36
+
37
+ // Bound variables
38
+ // --
39
+ // this.instance (A SirTrevor.Editor instance)
40
+
41
+ // Helper methods
42
+ // --
43
+ // this.save()
44
+ // this.loading()
45
+ // this.ready()
46
+ // this.uploadAttachment(file, callback)
47
+ // this.remove()
48
+
49
+ // Function; provide a custom validator.
50
+ // By default, we use a validator that checks for a class of 'required' on each input.
51
+ // This function *MUST* return true or false (whether it's valid or not)
52
+ // validate: function(){
53
+ // return true;
54
+ // },
55
+
56
+ // Function; Executed on render of the block if some data is provided.
57
+ // LoadData gives us a means to convert JSON data into the editor dom
58
+ // In this example we convert the text from markdown to HTML and show it inside the element
59
+ // returns null
60
+ loadData: function(data){
61
+ // this.$('.text-block').html(this.instance._toHTML(data.text, this.type));
62
+ },
63
+
64
+ // Function; Executed on save of the block, once the block is validated
65
+ // toData expects a way for the block to be transformed from inputs into JSON data
66
+ // The default toData function provides a pretty comprehensive way of turning data into JSON
67
+ // In this example we take the text data and save it to the data object on the block
68
+ toData: function(){
69
+ // Grab the data from the block (it's always stored on the data attr)
70
+ var dataStruct = this.$el.data('block');
71
+
72
+ // Grab the content input
73
+ var content = this.$('.text-block').html();
74
+
75
+ if (content.length > 0) {
76
+ // Convert it to markdown and store under the 'text' object
77
+ dataStruct.data.text = this.instance._toMarkdown(content, this.type);
78
+ }
79
+ },
80
+
81
+ // Function; Executed once content has been dropped onto the dropzone of this block
82
+ // Only required if you have enabled dropping and have provided a dropzone for this block
83
+ // Always is passed the ev.transferData object from the drop
84
+ // Please see the image block (https://github.com/madebymany/sir-trevor-js/blob/master/src/blocks/image.js) for an example
85
+ //onDrop: function(transferData) {},
86
+
87
+ // Function; Executed once content has been pasted into the block or any input field with the class 'paste-block'
88
+ // The default onContentPasted function strips all the HTML from a text-block, as shown here.
89
+ //onContentPasted: function(ev) {
90
+ // Convert to markdown and then to HTML to strip all unwanted markup
91
+ // this.$('.text-block').html(this.instance._toHTML(this.instance._toMarkdown(textBlock.html(), this.type)));
92
+ //},
93
+
94
+ // Function; Hook executed at the end of the block rendering method.
95
+ // Useful for initialising extra pieces of UI or binding extra events.
96
+ // In this example we add an extra button, just because.
97
+ // onBlockRender: function() {
98
+ // this.$el.append($('<button>', {
99
+ // click: function() {
100
+ // alert('Yo dawg, you clicked my button');
101
+ // }
102
+ // }));
103
+ // },
104
+
105
+ // Function; Optional hook method executed before the rendering of a block
106
+ // Beware, $el and any shorthand element variables won't be setup here.
107
+ // beforeBlockRender: function() {},
108
+
109
+ // Function; Any extra markdown parsing can be defined in here.
110
+ // Executed on the _.toMarkdown function of a SirTrevor.Editor instance
111
+ // Returns; String (Required)
112
+ // toMarkdown: function(markdown) {
113
+ // return markdown.replace(/^(.+)$/mg,"> $1");
114
+ // },
115
+
116
+ // Function; Any extra HTML parsing can be defined in here.
117
+ // Executed on the _.toHTML function of a SirTrevor.Editor instance
118
+ // Returns; String (Required)
119
+ // toHTML: function(html) {
120
+ // return html;
121
+ // }
122
+ });
@@ -0,0 +1,17 @@
1
+ require 'rails/generators'
2
+
3
+ module SirTrevor
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+
7
+ def self.source_root
8
+ @source_root ||= SirTrevor::Engine.root
9
+ end
10
+
11
+ def views
12
+ directory "app/views/sir-trevor/blocks"
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ require "active_support/dependencies"
2
+
3
+ module SirTrevor
4
+
5
+ mattr_accessor :app_root
6
+
7
+ module Helpers
8
+ autoload :ViewHelper, 'sir-trevor/helpers/view_helper'
9
+ autoload :FormHelper, 'sir-trevor/helpers/form_helper'
10
+ autoload :FormBuilder, 'sir-trevor/helpers/form_builder'
11
+ end
12
+
13
+ def self.setup
14
+ yield self
15
+ end
16
+
17
+ end
18
+
19
+ require "sir-trevor/engine"
@@ -0,0 +1,29 @@
1
+ module SirTrevor
2
+
3
+ class Engine < Rails::Engine
4
+
5
+ require 'redcarpet'
6
+ require 'twitter-text'
7
+
8
+ initializer "sir_trevor.load_app_instance_data" do |app|
9
+ SirTrevor.setup do |config|
10
+ config.app_root = app.root
11
+ end
12
+ end
13
+
14
+ initializer "sir_trevor.helpers" do
15
+ ActiveSupport.on_load :action_view do
16
+ ActionView::Base.send :include, SirTrevor::Helpers::ViewHelper
17
+ ActionView::Base.send :include, SirTrevor::Helpers::FormHelper
18
+ ActionView::Helpers::FormBuilder.send :include, SirTrevor::Helpers::FormBuilder
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.config(&block)
24
+ @@config ||= SirTrevor::Engine::Configuration.new
25
+ yield @@config if block
26
+ return @@config
27
+ end
28
+
29
+ end
@@ -0,0 +1,11 @@
1
+ module SirTrevor
2
+ module Helpers
3
+ module FormBuilder
4
+ extend ActiveSupport::Concern
5
+
6
+ def sir_trevor_text_area(method, options = {})
7
+ @template.send("sir_trevor_text_area", @object_name, method, objectify_options(options))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ module SirTrevor
2
+ module Helpers
3
+ module FormHelper
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ include ActionView::Helpers::TagHelper
8
+ include ActionView::Helpers::JavaScriptHelper
9
+
10
+ def sir_trevor_text_area(object_name, method, options = {})
11
+
12
+ options = { :language => I18n.locale.to_s }.merge(options)
13
+ input_html = (options.delete(:input_html) || {})
14
+ input_html['class'] = "sir-trevor-area visuallyhidden"
15
+ hash = input_html.stringify_keys
16
+
17
+ instance_tag = ActionView::Base::InstanceTag.new(object_name, method, self, options.delete(:object))
18
+ instance_tag.send(:add_default_name_and_id, hash)
19
+
20
+ output_buffer = ActiveSupport::SafeBuffer.new
21
+ output_buffer << instance_tag.to_text_area_tag(input_html)
22
+
23
+ output_buffer
24
+
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,78 @@
1
+ module SirTrevor
2
+ module Helpers
3
+ module ViewHelper
4
+
5
+ extend ActiveSupport::Concern
6
+ include Twitter::Autolink
7
+
8
+ def render_sir_trevor(json, image_type = "large")
9
+ hash = JSON.parse(json)
10
+
11
+ if hash.has_key?("data")
12
+ hash["data"].map { |object|
13
+ render(:partial => "sir-trevor/blocks/#{object["type"].to_s.downcase}_block", :locals => { :block => object['data'], :image_type => image_type, :protocol => request.protocol} ) if object.has_key?("data")
14
+ }.compact.join.html_safe
15
+ else
16
+ ''
17
+ end
18
+ end
19
+
20
+ def render_sir_trevor_image(json, image_type = "large")
21
+ image = pluck_sir_trevor_type(json, "image")
22
+
23
+ unless image.nil?
24
+ render(:partial => "sir-trevor/blocks/image_block", :locals => {:block => image['data'], :image_type => image_type, :protocol => request.protocol}) if image.has_key?("data")
25
+ end
26
+ end
27
+
28
+ def sir_trevor_image_tag(block, image_type)
29
+ # Does the image type exist on the block?
30
+ if(block['file'].present? && block['file'][image_type].present?)
31
+
32
+ image = block['file'][image_type]
33
+
34
+ image_url = image['url']
35
+ width = image['width'] if image['width'].present?
36
+ height = image['height'] if image['height'].present?
37
+
38
+ options = {
39
+ :class => "sir-trevor-image #{image_type}",
40
+ :alt => block['description']
41
+ }
42
+
43
+ options.merge!({ :width => width }) unless width.nil?
44
+ options.merge!({ :height => height }) unless height.nil?
45
+
46
+ image_tag(image_url, options) unless image_url.nil?
47
+ end
48
+ end
49
+
50
+ def sir_trevor_markdown(text)
51
+ options = {:hard_wrap => true, :filter_html => true, :autolink => true, :no_intraemphasis => true, :fenced_code => true}
52
+ renderer = Redcarpet::Render::HTML.new(options)
53
+ markdown = Redcarpet::Markdown.new(CustomMarkdownFormatter)
54
+ markdown.render(text).html_safe
55
+ end
56
+
57
+ private
58
+ # Get's the first instance of a type from the specified JSON
59
+ def pluck_sir_trevor_type(json, type)
60
+ hash = JSON.parse(json)
61
+ if hash.has_key?("data")
62
+ item = hash["data"].select { |item| item["type"] == type }
63
+ item.first
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ class CustomMarkdownFormatter < Redcarpet::Render::HTML
71
+ def block_code(code, language)
72
+ "<p>" << code << "</p>"
73
+ end
74
+
75
+ def codespan(code)
76
+ code
77
+ end
78
+ end
@@ -0,0 +1,3 @@
1
+ module SirTrevor
2
+ VERSION = "0.1.3"
3
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path("../lib/sir-trevor/version", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+
5
+ s.name = 'sir-trevor-rails'
6
+ s.version = SirTrevor::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.date = '2012-08-15'
9
+ s.summary = "sir-trevor-rails-#{s.version}"
10
+ s.description = "A structured text editor."
11
+ s.authors = ["Andrew Sprinz", "Chris Bell"]
12
+ s.email = 'chris@madebymany.com'
13
+ s.homepage = 'https://github.com/madebymany/sir-trevor-rails'
14
+
15
+ s.rubyforge_project = "sir-trevor-rails"
16
+ s.required_rubygems_version = "> 1.3.6"
17
+
18
+ s.add_dependency "activesupport" , ">= 3.0.7"
19
+ s.add_dependency "rails" , ">= 3.0.7"
20
+ s.add_dependency "jquery-rails"
21
+
22
+ s.add_dependency "redcarpet", "~> 2.0.1"
23
+ s.add_dependency 'twitter-text', '~> 1.4'
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
27
+ s.require_path = 'lib'
28
+
29
+ end