sir-trevor-rails 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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