texter 0.3.0 → 1.0.0

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.
@@ -1,33 +1,33 @@
1
1
  $(function(){
2
- $('body').on('click', '.js-edit', function(){
3
- EditText($(this));
4
- });
2
+ $('body').on('click', '.js-edit', function(){
3
+ EditText($(this));
4
+ });
5
5
 
6
- function EditText(elem){
6
+ function EditText(elem){
7
7
 
8
- function removePopup(){
9
- popup.fadeOut('fast', function(){
10
- popup.remove();
11
- });
12
- $(window).off('keyup');
13
- }
8
+ function removePopup(){
9
+ popup.fadeOut('fast', function(){
10
+ popup.remove();
11
+ });
12
+ $(window).off('keyup');
13
+ }
14
14
 
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
- });
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
- popup.on('click', '.close', function(){
24
- removePopup();
25
- });
23
+ popup.on('click', '.close', function(){
24
+ removePopup();
25
+ });
26
26
 
27
- $.get(elem.data('url'), function(){
28
- popup.fadeIn('fast', function(){
29
- popup.find('textarea:first').focus();
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
- Texter::CleanBody.new(@text).clean(Texter.bodies & @text.changed)
12
+ RunPreprocessorsOnText.call(@text)
15
13
 
16
- if @text.valid? && Texter::Typograph.new(@text).process(Texter.bodies & @text.changed)
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::TextFactory.new(path, tag_type, @virtual_path).build
13
- text.body
14
- end
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,11 @@
1
+ module Texter
2
+ module CallableClass
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def call(*args)
7
+ new(*args).call
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ module Texter
2
+ class CleanPreprocessor < Preprocessor
3
+ def call
4
+ body.to_s.gsub(/\r/, '').strip
5
+ end
6
+ end
7
+ 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,11 @@
1
+ module Texter
2
+ class SimpleFormatter < Formatter
3
+ def inline
4
+ body
5
+ end
6
+
7
+ def block
8
+ ApplicationController.helpers.simple_format(body)
9
+ end
10
+ end
11
+ 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
@@ -1,12 +1,12 @@
1
1
  module Texter
2
2
  class Text < ActiveRecord::Base
3
- TAG_TYPES = %w{block inline}
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 : I18n.t(path, {:scope => 'texts'}.merge(options)).strip
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 : TAG_TYPES.first
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 "Сохранить", :disable_with => '✔ Сохраняется...' %>
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
- $(".<%= @text.path_for_class %>").each(function(){
3
- $(this).replaceWith($("<%= j(@text.body) %>"));
3
+ $(".<%= presenter.path_for_class %>").each(function(){
4
+ $(this).replaceWith($("<%= j(presenter.body) %>"));
4
5
  });
@@ -0,0 +1,10 @@
1
+ ru:
2
+ texter:
3
+ edit: Редактировать
4
+ submit: Сохранить
5
+ disable_with: '✔ Сохраняется...'
6
+
7
+ simple_form:
8
+ labels:
9
+ text:
10
+ body: Текст
@@ -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, :default => ''
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 "texter/engine"
1
+ require 'texter/engine'
2
+ require 'simple_form'
2
3
 
3
4
  module Texter
4
- # body attributes for text, array of strings
5
- # it can be %w{body_ru body_en} for instance, if you use multiple languages
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
- mattr_accessor :controller_setup
10
- self.controller_setup = proc{|controller| controller.before_filter(:require_moderator!)}
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
@@ -1,11 +1,3 @@
1
- require 'draper'
2
- require 'simple_form'
3
- require 'RedCloth'
4
- require 'art_typograph'
5
- require 'texter/typograph'
6
- require 'texter/clean_body'
7
- require 'texter/text_factory'
8
-
9
1
  module Texter
10
2
  class Engine < ::Rails::Engine
11
3
  isolate_namespace Texter
@@ -1,3 +1,3 @@
1
1
  module Texter
2
- VERSION = "0.3.0"
2
+ VERSION = "1.0.0"
3
3
  end
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.3.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-02-16 00:00:00.000000000 Z
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: draper
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: 1.1.0
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: 1.1.0
61
+ version: '0'
62
62
  - !ruby/object:Gem::Dependency
63
- name: RedCloth
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: 4.2.9
70
- type: :runtime
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: 4.2.9
77
+ version: '2.12'
78
78
  - !ruby/object:Gem::Dependency
79
- name: simple_form
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: '0'
86
- type: :runtime
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: '0'
93
+ version: 2.0.1
94
94
  - !ruby/object:Gem::Dependency
95
- name: art_typograph
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: :runtime
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: rspec-rails
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: '2.12'
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: '2.12'
125
+ version: '0'
126
126
  - !ruby/object:Gem::Dependency
127
- name: capybara
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: 2.0.1
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: 2.0.1
141
+ version: '0'
142
142
  - !ruby/object:Gem::Dependency
143
- name: sqlite3
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: '0'
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: '0'
157
+ version: 4.2.9
158
158
  - !ruby/object:Gem::Dependency
159
- name: database_cleaner
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: '0'
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: '0'
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
@@ -1,11 +0,0 @@
1
- module Texter
2
- class CleanBody < Struct.new(:text)
3
- def clean(*attrs)
4
- attrs.flatten.each do |attr|
5
- if (value = text.send(attr)).present?
6
- text.send("#{attr}=", value.gsub(/\r/, ''))
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -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
@@ -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