texter 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/app/assets/javascripts/texter/texts.js +26 -26
- data/app/controllers/texter/texts_controller.rb +2 -5
- data/app/helpers/texter/texts_helper.rb +8 -35
- data/app/lib/texter/art_typograph_preprocessor.rb +13 -0
- data/app/lib/texter/build_text.rb +38 -0
- data/app/lib/texter/callable_class.rb +11 -0
- data/app/lib/texter/clean_preprocessor.rb +7 -0
- data/app/lib/texter/formatter.rb +26 -0
- data/app/lib/texter/markdown_formatter.rb +41 -0
- data/app/lib/texter/preprocessor.rb +17 -0
- data/app/lib/texter/run_preprocessors_on_text.rb +29 -0
- data/app/lib/texter/simple_formatter.rb +11 -0
- data/app/lib/texter/textile_formatter.rb +42 -0
- data/app/models/texter/text.rb +6 -6
- data/app/presenters/texter/text_presenter.rb +60 -0
- data/app/views/texter/texts/_edit.html.erb +1 -1
- data/app/views/texter/texts/update.js.erb +3 -2
- data/config/locales/texter.ru.yml +10 -0
- data/db/migrate/20121231021051_create_texter_texts.rb +1 -2
- data/lib/texter.rb +27 -5
- data/lib/texter/engine.rb +0 -8
- data/lib/texter/version.rb +1 -1
- metadata +61 -51
- data/app/decorators/texter/text_decorator.rb +0 -42
- data/lib/texter/clean_body.rb +0 -11
- data/lib/texter/text_factory.rb +0 -23
- data/lib/texter/typograph.rb +0 -21
@@ -1,33 +1,33 @@
|
|
1
1
|
$(function(){
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
$('body').on('click', '.js-edit', function(){
|
3
|
+
EditText($(this));
|
4
|
+
});
|
5
5
|
|
6
|
-
|
6
|
+
function EditText(elem){
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
function removePopup(){
|
9
|
+
popup.fadeOut('fast', function(){
|
10
|
+
popup.remove();
|
11
|
+
});
|
12
|
+
$(window).off('keyup');
|
13
|
+
}
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
$('body').append('<div id="popup"><span class="close"></span><div id="form"></div></div>');
|
16
|
+
var popup = $('#popup');
|
17
|
+
$(window).on('keyup', function(e){
|
18
|
+
if(e.keyCode == 27){
|
19
|
+
removePopup();
|
20
|
+
}
|
21
|
+
});
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
popup.on('click', '.close', function(){
|
24
|
+
removePopup();
|
25
|
+
});
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
$.get(elem.data('url'), function(){
|
28
|
+
popup.fadeIn('fast', function(){
|
29
|
+
popup.find('textarea:first').focus();
|
30
|
+
});
|
31
|
+
});
|
32
|
+
}
|
33
33
|
});
|
@@ -2,8 +2,6 @@ require_dependency "texter/application_controller"
|
|
2
2
|
|
3
3
|
module Texter
|
4
4
|
class TextsController < ApplicationController
|
5
|
-
Texter.controller_setup.call(self)
|
6
|
-
|
7
5
|
respond_to :js
|
8
6
|
before_filter :load_text
|
9
7
|
|
@@ -11,10 +9,9 @@ module Texter
|
|
11
9
|
end
|
12
10
|
|
13
11
|
def update
|
14
|
-
|
12
|
+
RunPreprocessorsOnText.call(@text)
|
15
13
|
|
16
|
-
if @text.
|
17
|
-
@text = TextDecorator.new(@text)
|
14
|
+
if @text.save
|
18
15
|
render :update
|
19
16
|
else
|
20
17
|
render :edit
|
@@ -1,44 +1,17 @@
|
|
1
1
|
module Texter
|
2
2
|
module TextsHelper
|
3
|
-
def inline(path)
|
4
|
-
display_text(path, :inline)
|
3
|
+
def inline(path, options = {})
|
4
|
+
display_text(path, :inline, options)
|
5
5
|
end
|
6
6
|
|
7
|
-
def block(path)
|
8
|
-
display_text(path, :block)
|
7
|
+
def block(path, options = {})
|
8
|
+
display_text(path, :block, options)
|
9
9
|
end
|
10
10
|
|
11
|
-
def display_text(path, tag_type)
|
12
|
-
text = Texter::
|
13
|
-
text
|
14
|
-
|
15
|
-
|
16
|
-
def text_can_be_edited?(text)
|
17
|
-
moderator_signed_in?
|
18
|
-
end
|
19
|
-
|
20
|
-
def textile(string, *rules)
|
21
|
-
return nil if string.blank?
|
22
|
-
|
23
|
-
textilize = ::RedCloth.new(string, rules)
|
24
|
-
textilize.to_html(:block_textile_prefix, :block_textile_lists, :inline_textile_link).html_safe
|
25
|
-
|
26
|
-
# refs_textile:: Textile references (i.e. [hobix]http://hobix.com/)
|
27
|
-
# block_textile_table:: Textile table block structures
|
28
|
-
# block_textile_lists:: Textile list structures
|
29
|
-
# block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h2., etc.)
|
30
|
-
# inline_textile_image:: Textile inline images
|
31
|
-
# inline_textile_link:: Textile inline links
|
32
|
-
# inline_textile_span:: Textile inline spans
|
33
|
-
# inline_textile_glyphs:: Textile entities (such as em-dashes and smart quotes)
|
34
|
-
end
|
35
|
-
|
36
|
-
def textile_block(string)
|
37
|
-
textile(string)
|
38
|
-
end
|
39
|
-
|
40
|
-
def textile_inline(string)
|
41
|
-
textile(string, :lite_mode)
|
11
|
+
def display_text(path, tag_type, options = {})
|
12
|
+
text = Texter::BuildText.call(path, tag_type, @virtual_path)
|
13
|
+
presenter = Texter::TextPresenter.new(text, self, options)
|
14
|
+
presenter.body
|
42
15
|
end
|
43
16
|
end
|
44
17
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'art_typograph'
|
2
|
+
|
3
|
+
module Texter
|
4
|
+
class ArtTypographPreprocessor < Preprocessor
|
5
|
+
def call
|
6
|
+
processed = ArtTypograph.process(body)
|
7
|
+
processed.gsub! %r{</p>}m, "\n"
|
8
|
+
processed.gsub! %r{<p.*?>}, ''
|
9
|
+
processed.gsub! %r{</?(nobr|span).*?>}, ''
|
10
|
+
processed.strip
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Texter
|
2
|
+
class BuildText
|
3
|
+
include CallableClass
|
4
|
+
|
5
|
+
attr_reader :path, :tag_type, :virtual_path
|
6
|
+
|
7
|
+
# @param [String] path
|
8
|
+
# @param [Symbol] tag_type (:block, :inline)
|
9
|
+
# @param [String, NilClass] virtual_path
|
10
|
+
def initialize(path, tag_type, virtual_path)
|
11
|
+
@path = path
|
12
|
+
@tag_type = tag_type
|
13
|
+
@virtual_path = virtual_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
text = Texter::Text.find_or_initialize_by_path(full_path)
|
18
|
+
text.tag_type = tag_type
|
19
|
+
text
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def full_path
|
25
|
+
return path unless relative_path?
|
26
|
+
|
27
|
+
if virtual_path
|
28
|
+
virtual_path.gsub(%r{/_?}, ".") + path.to_s
|
29
|
+
else
|
30
|
+
raise "Cannot use #{path.inspect} shortcut because path is not available"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def relative_path?
|
35
|
+
path.starts_with?(".")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Texter
|
2
|
+
class Formatter
|
3
|
+
attr_reader :body, :options
|
4
|
+
|
5
|
+
def initialize(body, options = {})
|
6
|
+
@body = body
|
7
|
+
@options = options.dup
|
8
|
+
reverse_merge_defaults
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String, NilClass]
|
12
|
+
def inline
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [String, NilClass]
|
17
|
+
def block
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def reverse_merge_defaults
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rdiscount'
|
2
|
+
|
3
|
+
module Texter
|
4
|
+
class MarkdownFormatter < Formatter
|
5
|
+
# :smart - Enable SmartyPants processing.
|
6
|
+
# :filter_styles - Do not output <style> tags.
|
7
|
+
# :filter_html - Do not output any raw HTML tags included in the source text.
|
8
|
+
# :fold_lines - RedCloth compatible line folding (not used).
|
9
|
+
# :footnotes - PHP markdown extra-style footnotes.
|
10
|
+
# :generate_toc - Enable Table Of Contents generation
|
11
|
+
# :no_image - Do not output any <img> tags.
|
12
|
+
# :no_links - Do not output any <a> tags.
|
13
|
+
# :no_tables - Do not output any tables.
|
14
|
+
# :strict - Disable superscript and relaxed emphasis processing.
|
15
|
+
# :autolink - Greedily urlify links.
|
16
|
+
# :safelink - Do not make links for unknown URL types.
|
17
|
+
# :no_pseudo_protocols - Do not process pseudo-protocols.
|
18
|
+
cattr_accessor :extensions
|
19
|
+
self.extensions = []
|
20
|
+
|
21
|
+
# extracts html from the first paragraph or header
|
22
|
+
def inline
|
23
|
+
block.match(%r{<[hp]\d?>(.*?)</[hp]\d?>}).try(:[], 1)
|
24
|
+
end
|
25
|
+
|
26
|
+
def block
|
27
|
+
return nil if body.blank?
|
28
|
+
|
29
|
+
markdown = ::RDiscount.new(body, *options[:extensions])
|
30
|
+
markdown.to_html
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def reverse_merge_defaults
|
36
|
+
options.assert_valid_keys(:extensions)
|
37
|
+
options.reverse_merge!(:extensions => extensions)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Texter
|
2
|
+
class Preprocessor
|
3
|
+
include CallableClass
|
4
|
+
|
5
|
+
attr_reader :body
|
6
|
+
|
7
|
+
# @param [String] body
|
8
|
+
def initialize(body)
|
9
|
+
@body = body
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [String, NilClass]
|
13
|
+
def call
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Texter
|
2
|
+
class RunPreprocessorsOnText
|
3
|
+
include CallableClass
|
4
|
+
|
5
|
+
attr_reader :text, :options
|
6
|
+
|
7
|
+
# @param [Texter::Text] text
|
8
|
+
# @param [Hash] options (:force => true to force processing)
|
9
|
+
def initialize(text, options = {})
|
10
|
+
@text = text
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
attributes.each do |attr|
|
16
|
+
body = text.send(attr)
|
17
|
+
processed = Texter.preprocessors.inject(body) { |memo, preprocessor| Texter.find_preprocessor(preprocessor).call(memo) }
|
18
|
+
text.send "#{attr}=", processed
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def attributes
|
25
|
+
return Texter.bodies if options[:force]
|
26
|
+
Texter.bodies & text.changed
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'RedCloth'
|
2
|
+
|
3
|
+
module Texter
|
4
|
+
class TextileFormatter < Formatter
|
5
|
+
cattr_accessor :rules, :restrictions
|
6
|
+
|
7
|
+
self.rules = []
|
8
|
+
|
9
|
+
# :filter_html
|
10
|
+
# :sanitize_html
|
11
|
+
# :filter_styles
|
12
|
+
# :filter_classes
|
13
|
+
# :filter_ids
|
14
|
+
# :lite_mode
|
15
|
+
# :no_span_caps
|
16
|
+
self.restrictions = [:no_span_caps]
|
17
|
+
|
18
|
+
def inline
|
19
|
+
restrictions_with_lite_mode = (options[:restrictions] + [:lite_mode]).uniq
|
20
|
+
textile :restrictions => restrictions_with_lite_mode
|
21
|
+
end
|
22
|
+
|
23
|
+
def block
|
24
|
+
textile
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def textile(redefine_options = {})
|
30
|
+
return nil if body.blank?
|
31
|
+
|
32
|
+
redefined_options = options.merge(redefine_options)
|
33
|
+
textile = ::RedCloth.new(body, redefined_options[:restrictions])
|
34
|
+
textile.to_html(*redefined_options[:rules]).html_safe
|
35
|
+
end
|
36
|
+
|
37
|
+
def reverse_merge_defaults
|
38
|
+
options.assert_valid_keys(:rules, :restrictions)
|
39
|
+
options.reverse_merge!(:rules => rules, :restrictions => restrictions)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/app/models/texter/text.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module Texter
|
2
2
|
class Text < ActiveRecord::Base
|
3
|
-
|
3
|
+
BLOCK = 'block'
|
4
|
+
TAG_TYPES = [BLOCK, 'inline']
|
5
|
+
|
4
6
|
attr_writer :tag_type
|
5
7
|
|
6
8
|
attr_accessible *Texter.bodies, :tag_type
|
7
|
-
|
8
9
|
validates_uniqueness_of :path, :allow_blank => false
|
9
|
-
validates_presence_of *Texter.bodies
|
10
10
|
|
11
11
|
def self.find_or_create_from_translations_by_path(path)
|
12
12
|
text = find_or_initialize_by_path(path)
|
@@ -19,15 +19,15 @@ module Texter
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def get_body(options = {})
|
22
|
-
persisted? ? body :
|
22
|
+
persisted? ? body : Texter.translate(path, options)
|
23
23
|
end
|
24
24
|
|
25
25
|
def tag_type
|
26
|
-
TAG_TYPES.include?(@tag_type.to_s) ? @tag_type :
|
26
|
+
TAG_TYPES.include?(@tag_type.to_s) ? @tag_type : BLOCK
|
27
27
|
end
|
28
28
|
|
29
29
|
def default_attributes
|
30
|
-
{:body => get_body}
|
30
|
+
{ :body => get_body }
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module Texter
|
3
|
+
class TextPresenter
|
4
|
+
attr_reader :text, :h, :options
|
5
|
+
|
6
|
+
delegate :tag_type, :get_body, :path, :to => :text
|
7
|
+
|
8
|
+
def initialize(text, h, options = {})
|
9
|
+
@text = text
|
10
|
+
@h = h
|
11
|
+
@options = options
|
12
|
+
|
13
|
+
options.assert_valid_keys(:locale, :formatter, :formatter_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def body
|
17
|
+
return formatted unless can_be_edited?
|
18
|
+
|
19
|
+
h.content_tag(content_tag_name, formatted, {
|
20
|
+
:data => {
|
21
|
+
:url => h.texter.edit_text_path(path, :js, :text => {
|
22
|
+
:tag_type => tag_type
|
23
|
+
})
|
24
|
+
},
|
25
|
+
:class => "js-edit #{path_for_class}"
|
26
|
+
})
|
27
|
+
end
|
28
|
+
|
29
|
+
def path_for_class
|
30
|
+
path.gsub(/\./, '-')
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def formatter
|
36
|
+
Texter.find_formatter(options[:formatter] || Texter.formatter)
|
37
|
+
end
|
38
|
+
|
39
|
+
def content_tag_name
|
40
|
+
{
|
41
|
+
:block => :div,
|
42
|
+
:inline => :span
|
43
|
+
}.fetch(tag_type.to_sym)
|
44
|
+
end
|
45
|
+
|
46
|
+
def formatted
|
47
|
+
body = get_body(locale_options)
|
48
|
+
body = Texter.translate("edit", locale_options.merge(:default => 'Редактировать')) if can_be_edited? && body.blank?
|
49
|
+
formatter.new(body, options[:formatter_options] || {}).send(tag_type)
|
50
|
+
end
|
51
|
+
|
52
|
+
def can_be_edited?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def locale_options
|
57
|
+
options.slice(:locale)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -3,5 +3,5 @@
|
|
3
3
|
<% Texter.bodies.each do |body| %>
|
4
4
|
<%= f.input body %>
|
5
5
|
<% end %>
|
6
|
-
<%= f.submit
|
6
|
+
<%= f.submit Texter.translate('submit', :default => 'Сохранить'), :disable_with => Texter.translate('disable_with', :default => '✔ Сохраняется...') %>
|
7
7
|
<% end %>
|
@@ -1,4 +1,5 @@
|
|
1
|
+
<% presenter = Texter::TextPresenter.new(@text, self) %>
|
1
2
|
$("#popup").remove();
|
2
|
-
$(".<%=
|
3
|
-
$(this).replaceWith($("<%= j(
|
3
|
+
$(".<%= presenter.path_for_class %>").each(function(){
|
4
|
+
$(this).replaceWith($("<%= j(presenter.body) %>"));
|
4
5
|
});
|
@@ -1,9 +1,8 @@
|
|
1
1
|
class CreateTexterTexts < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :texter_texts do |t|
|
4
|
-
t.string :path, :null => false
|
4
|
+
t.string :path, :null => false
|
5
5
|
t.text :body
|
6
|
-
t.timestamps
|
7
6
|
end
|
8
7
|
add_index :texter_texts, :path, :unique => true
|
9
8
|
end
|
data/lib/texter.rb
CHANGED
@@ -1,11 +1,33 @@
|
|
1
|
-
require
|
1
|
+
require 'texter/engine'
|
2
|
+
require 'simple_form'
|
2
3
|
|
3
4
|
module Texter
|
4
|
-
# body attributes for text
|
5
|
-
# it can be %w{body_ru body_en} for instance
|
5
|
+
# [Array<String>] body attributes for text
|
6
|
+
# it can be %w{body_ru body_en} for instance if you use multiple languages
|
6
7
|
mattr_accessor :bodies
|
7
8
|
self.bodies = %w{body}
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
# [Array<Symbol>]
|
11
|
+
mattr_accessor :preprocessors
|
12
|
+
self.preprocessors = [:clean]
|
13
|
+
|
14
|
+
# [Symbol]
|
15
|
+
mattr_accessor :formatter
|
16
|
+
self.formatter = :simple
|
17
|
+
|
18
|
+
class <<self
|
19
|
+
# @param [Symbol, String] name
|
20
|
+
def find_formatter(name)
|
21
|
+
"Texter::#{name.to_s.classify}Formatter".constantize
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [Symbol, String] name
|
25
|
+
def find_preprocessor(name)
|
26
|
+
"Texter::#{name.to_s.classify}Preprocessor".constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def translate(path, options = {})
|
30
|
+
I18n.t(path, { :scope => 'texter' }.merge(options))
|
31
|
+
end
|
32
|
+
end
|
11
33
|
end
|
data/lib/texter/engine.rb
CHANGED
data/lib/texter/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: texter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,14 +9,14 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-07-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: 3.2.9
|
22
22
|
type: :runtime
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 3.2.9
|
30
30
|
- !ruby/object:Gem::Dependency
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: 3.2.3
|
38
38
|
type: :runtime
|
@@ -40,66 +40,66 @@ dependencies:
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 3.2.3
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: simple_form
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
53
|
+
version: '0'
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: '0'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: rspec-rails
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
67
|
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
70
|
-
type: :
|
69
|
+
version: '2.12'
|
70
|
+
type: :development
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: '2.12'
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: capybara
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
86
|
-
type: :
|
85
|
+
version: 2.0.1
|
86
|
+
type: :development
|
87
87
|
prerelease: false
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
89
|
none: false
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
93
|
+
version: 2.0.1
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: sqlite3
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
99
|
- - ! '>='
|
100
100
|
- !ruby/object:Gem::Version
|
101
101
|
version: '0'
|
102
|
-
type: :
|
102
|
+
type: :development
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
@@ -108,76 +108,77 @@ dependencies:
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
111
|
+
name: database_cleaner
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
113
113
|
none: false
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ! '>='
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
none: false
|
122
122
|
requirements:
|
123
|
-
- -
|
123
|
+
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: '
|
125
|
+
version: '0'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
|
-
name:
|
127
|
+
name: rdiscount
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
|
-
- -
|
131
|
+
- - ! '>='
|
132
132
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
133
|
+
version: '0'
|
134
134
|
type: :development
|
135
135
|
prerelease: false
|
136
136
|
version_requirements: !ruby/object:Gem::Requirement
|
137
137
|
none: false
|
138
138
|
requirements:
|
139
|
-
- -
|
139
|
+
- - ! '>='
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version:
|
141
|
+
version: '0'
|
142
142
|
- !ruby/object:Gem::Dependency
|
143
|
-
name:
|
143
|
+
name: RedCloth
|
144
144
|
requirement: !ruby/object:Gem::Requirement
|
145
145
|
none: false
|
146
146
|
requirements:
|
147
|
-
- -
|
147
|
+
- - ~>
|
148
148
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
149
|
+
version: 4.2.9
|
150
150
|
type: :development
|
151
151
|
prerelease: false
|
152
152
|
version_requirements: !ruby/object:Gem::Requirement
|
153
153
|
none: false
|
154
154
|
requirements:
|
155
|
-
- -
|
155
|
+
- - ~>
|
156
156
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
157
|
+
version: 4.2.9
|
158
158
|
- !ruby/object:Gem::Dependency
|
159
|
-
name:
|
159
|
+
name: art_typograph
|
160
160
|
requirement: !ruby/object:Gem::Requirement
|
161
161
|
none: false
|
162
162
|
requirements:
|
163
|
-
- -
|
163
|
+
- - ~>
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
165
|
+
version: 0.1.1
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
none: false
|
170
170
|
requirements:
|
171
|
-
- -
|
171
|
+
- - ~>
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
173
|
+
version: 0.1.1
|
174
174
|
description: ! '* Лёгкий вывод блочных и инлайновых текстов, отформатированных с помощью
|
175
|
-
Textile
|
175
|
+
Textile, Markdown или simple_format
|
176
176
|
|
177
177
|
* Дефолтные тексты в I18n
|
178
178
|
|
179
|
-
*
|
180
|
-
|
179
|
+
* При редактировании тексты сохраняются в базе
|
180
|
+
|
181
|
+
* Подключаемые обработчики (препроцессоры) — можно легко подключить «Типограф Лебедева»
|
181
182
|
|
182
183
|
* Удобный, встроенный в сайт интерфейс редактирования'
|
183
184
|
email:
|
@@ -193,26 +194,35 @@ files:
|
|
193
194
|
- app/assets/stylesheets/texter/application.css
|
194
195
|
- app/controllers/texter/application_controller.rb
|
195
196
|
- app/controllers/texter/texts_controller.rb
|
196
|
-
- app/decorators/texter/text_decorator.rb
|
197
197
|
- app/helpers/texter/application_helper.rb
|
198
198
|
- app/helpers/texter/texts_helper.rb
|
199
|
+
- app/lib/texter/art_typograph_preprocessor.rb
|
200
|
+
- app/lib/texter/build_text.rb
|
201
|
+
- app/lib/texter/callable_class.rb
|
202
|
+
- app/lib/texter/clean_preprocessor.rb
|
203
|
+
- app/lib/texter/formatter.rb
|
204
|
+
- app/lib/texter/markdown_formatter.rb
|
205
|
+
- app/lib/texter/preprocessor.rb
|
206
|
+
- app/lib/texter/run_preprocessors_on_text.rb
|
207
|
+
- app/lib/texter/simple_formatter.rb
|
208
|
+
- app/lib/texter/textile_formatter.rb
|
199
209
|
- app/models/texter/text.rb
|
210
|
+
- app/presenters/texter/text_presenter.rb
|
200
211
|
- app/views/texter/texts/_edit.html.erb
|
201
212
|
- app/views/texter/texts/edit.js.erb
|
202
213
|
- app/views/texter/texts/update.js.erb
|
214
|
+
- config/locales/texter.ru.yml
|
203
215
|
- config/routes.rb
|
204
216
|
- db/migrate/20121231021051_create_texter_texts.rb
|
205
217
|
- lib/tasks/texter_tasks.rake
|
206
|
-
- lib/texter/clean_body.rb
|
207
218
|
- lib/texter/engine.rb
|
208
|
-
- lib/texter/text_factory.rb
|
209
|
-
- lib/texter/typograph.rb
|
210
219
|
- lib/texter/version.rb
|
211
220
|
- lib/texter.rb
|
212
221
|
- Rakefile
|
213
222
|
homepage: http://github.com/macovsky/texter
|
214
223
|
licenses: []
|
215
|
-
post_install_message:
|
224
|
+
post_install_message: Texter 1.0.0 is backwards incompatible, please take a look at
|
225
|
+
the changelog.
|
216
226
|
rdoc_options: []
|
217
227
|
require_paths:
|
218
228
|
- lib
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require 'draper'
|
3
|
-
|
4
|
-
module Texter
|
5
|
-
class TextDecorator < Draper::Decorator
|
6
|
-
decorates 'Texter::Text'
|
7
|
-
delegate_all
|
8
|
-
|
9
|
-
def body
|
10
|
-
return textile unless can_edit?
|
11
|
-
|
12
|
-
h.content_tag(content_tag, textile, {
|
13
|
-
:data => {
|
14
|
-
:url => h.texter.edit_text_path(path, :js, :text => {
|
15
|
-
:tag_type => tag_type
|
16
|
-
})
|
17
|
-
},
|
18
|
-
:class => "js-edit #{path_for_class}"
|
19
|
-
})
|
20
|
-
end
|
21
|
-
|
22
|
-
def path_for_class
|
23
|
-
path.gsub(/\./, '-')
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def content_tag
|
29
|
-
{:block => :div, :inline => :span}[tag_type.to_sym]
|
30
|
-
end
|
31
|
-
|
32
|
-
def textile
|
33
|
-
body = get_body
|
34
|
-
body = "Редактировать" if can_edit? && body.blank?
|
35
|
-
h.send("textile_#{tag_type}", body)
|
36
|
-
end
|
37
|
-
|
38
|
-
def can_edit?
|
39
|
-
h.text_can_be_edited?(model)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/texter/clean_body.rb
DELETED
data/lib/texter/text_factory.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
module Texter
|
2
|
-
class TextFactory < Struct.new(:path, :tag_type, :virtual_path)
|
3
|
-
def build
|
4
|
-
text = Texter::Text.find_or_initialize_by_path(full_path)
|
5
|
-
text.tag_type = tag_type
|
6
|
-
Texter::TextDecorator.new(text)
|
7
|
-
end
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
def full_path
|
12
|
-
if path.to_s.first == "."
|
13
|
-
if virtual_path
|
14
|
-
virtual_path.gsub(%r{/_?}, ".") + path.to_s
|
15
|
-
else
|
16
|
-
raise "Cannot use #{path.inspect} shortcut because path is not available"
|
17
|
-
end
|
18
|
-
else
|
19
|
-
path
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/lib/texter/typograph.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Texter
|
2
|
-
class Typograph < Struct.new(:text)
|
3
|
-
def process(*attrs)
|
4
|
-
return true if attrs.blank?
|
5
|
-
|
6
|
-
options = attrs.flatten.inject({}){|memo, attr|
|
7
|
-
memo.merge! attr => self.class.process(text.send(attr))
|
8
|
-
}
|
9
|
-
|
10
|
-
text.update_attributes options
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.process(text)
|
14
|
-
s = ArtTypograph.process(text)
|
15
|
-
s.gsub! %r{</p>}m, "\n"
|
16
|
-
s.gsub! %r{<p.*?>}, ''
|
17
|
-
s.gsub! %r{</?(nobr|span).*?>}, ''
|
18
|
-
s.strip
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|