sir-trevor-rails 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +101 -0
- data/MIT-LICENCE +20 -0
- data/README.md +120 -0
- data/Rakefile +10 -0
- data/app/assets/images/sir-trevor/icons/block_editor_blockquote.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_embed.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_image.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_list.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_text.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_tweet.png +0 -0
- data/app/assets/images/sir-trevor/icons/block_editor_video.png +0 -0
- data/app/assets/images/sir-trevor/icons/close.gif +0 -0
- data/app/assets/images/sir-trevor/icons/handle.gif +0 -0
- data/app/assets/images/sir-trevor/icons/new_image.png +0 -0
- data/app/assets/images/sir-trevor/icons/new_tweet.png +0 -0
- data/app/assets/images/sir-trevor/icons/new_video.png +0 -0
- data/app/assets/images/sir-trevor/icons/quote.png +0 -0
- data/app/assets/images/sir-trevor/placeholders/placeholder.jpg +0 -0
- data/app/assets/images/sir-trevor/placeholders/post_placeholder.jpg +0 -0
- data/app/assets/images/sir-trevor/placeholders/thumbnail_placeholder.jpg +0 -0
- data/app/assets/javascript/sir-trevor.js +2 -0
- data/app/assets/javascript/sir-trevor/libs/underscore.js +32 -0
- data/app/assets/javascript/sir-trevor/sir-trevor.js +2363 -0
- data/app/assets/stylesheets/sir-trevor.css +4 -0
- data/app/assets/stylesheets/sir-trevor/icons.css.erb +47 -0
- data/app/assets/stylesheets/sir-trevor/sir-trevor.css +551 -0
- data/app/views/sir-trevor/blocks/_gallery_block.html.erb +6 -0
- data/app/views/sir-trevor/blocks/_image_block.html.erb +3 -0
- data/app/views/sir-trevor/blocks/_quote_block.html.erb +4 -0
- data/app/views/sir-trevor/blocks/_text_block.html.erb +3 -0
- data/app/views/sir-trevor/blocks/_tweet_block.html.erb +6 -0
- data/app/views/sir-trevor/blocks/_ul_block.html.erb +3 -0
- data/app/views/sir-trevor/blocks/_video_block.html.erb +7 -0
- data/config/initializers/validators.rb +10 -0
- data/lib/generators/sir_trevor/block/block_generator.rb +37 -0
- data/lib/generators/sir_trevor/block/templates/_block.css.erb +7 -0
- data/lib/generators/sir_trevor/block/templates/_block.html.erb +3 -0
- data/lib/generators/sir_trevor/block/templates/_block.js +122 -0
- data/lib/generators/sir_trevor/block/templates/_block.png +0 -0
- data/lib/generators/sir_trevor/views/views_generator.rb +17 -0
- data/lib/sir-trevor-rails.rb +19 -0
- data/lib/sir-trevor/engine.rb +29 -0
- data/lib/sir-trevor/helpers/form_builder.rb +11 -0
- data/lib/sir-trevor/helpers/form_helper.rb +29 -0
- data/lib/sir-trevor/helpers/view_helper.rb +78 -0
- data/lib/sir-trevor/version.rb +3 -0
- data/sir-trevor-rails.gemspec +29 -0
- 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,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,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&byline=1&portrait=1&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,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
|
+
});
|
Binary file
|
@@ -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,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,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
|