texter 0.3.0 → 1.0.0

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