publify_core 10.0.0 → 10.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 315c96f6777f5d761c19b1b78a37aa38fdddb337522c56059813be2340f835cd
4
- data.tar.gz: cd54077be1d63bfd63e385e2dd61e2f23e2928ba3e19ef9aa04f69ab94e00263
3
+ metadata.gz: f07659f73a5dbeb0204128c9d42e6fcec4092ed7d4e920dceac39f1d104531f3
4
+ data.tar.gz: cef962bcdc17d957b1824f6e529534c48fdadb473280c910a33198cbcb49d2e7
5
5
  SHA512:
6
- metadata.gz: af4a6c89bc46ba69993175cbc0245c8cda50e5818a0d809322c5ff9a3431848c8c3b1e5b38db15e8a1ec2e226f3127978b25d312c4e91039af436eba950d2889
7
- data.tar.gz: 114fd493221442b2d93dd40cf8c2766cd7b18e1d07a843fe14b605a44e1745a38b4481ccf4f83bf24afd378bb7d525ebd812e4b2bb8dfef3bcff6b7b18db13ba
6
+ metadata.gz: 5f1262b50e741c94cf9bfcf2cc9d30dade5ae00fccbb5a33206789e7a900af47d280246b204b4f6671f2baaf18547fa1c98aad558d890500347ce58cf97d14f6
7
+ data.tar.gz: 58e3228983425a5a802714855453184d726f351b81475c0f36f63acf19486c61c0be3f54b26a5cb205f0db48924158840a978fb83888c33cbbcaeaddc9d65b98
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 10.0.1 / 2023-10-28
4
+
5
+ * Update CarrierWave dependency to version 3.0 ([#102] by [mvz])
6
+ * Move String monkey-patches into a module under PublifyCore ([#115] by [mvz])
7
+ * Remove text filter plugin naming requirements ([#109], [#110], [#117] by [mvz])
8
+ * Fix name and description of Twitterfilter ([#118] by [mvz])
9
+ * Fix link to pull request in CHANGELOG ([#116] by [mvz])
10
+ * Provide proper validation feedback during setup ([#119] by [mvz])
11
+
12
+ [#102]: https://github.com/publify/publify_core/pull/102
13
+ [#109]: https://github.com/publify/publify_core/pull/109
14
+ [#110]: https://github.com/publify/publify_core/pull/110
15
+ [#115]: https://github.com/publify/publify_core/pull/115
16
+ [#116]: https://github.com/publify/publify_core/pull/116
17
+ [#117]: https://github.com/publify/publify_core/pull/117
18
+ [#118]: https://github.com/publify/publify_core/pull/118
19
+ [#119]: https://github.com/publify/publify_core/pull/119
20
+ [mvz]: https://github.com/mvz
21
+ [dependabot]: https://github.com/apps/dependabot
22
+
3
23
  ## 10.0.0 / 2023-06-25
4
24
 
5
25
  ### Updated dependencies
@@ -37,7 +57,7 @@
37
57
  * Remove `sitealizer` table [publify#1089](https://github.com/publify/publify/pull/1089) by [SupriyaMedankar](https://github.com/SupriyaMedankar)
38
58
  * Remove itunes fields from resources [publify#1092](https://github.com/publify/publify/pull/1092) by [SupriyaMedankar](https://github.com/SupriyaMedankar)
39
59
  * Remove `page_caches` table [publify#1090](https://github.com/publify/publify/pull/1090) by [SupriyaMedankar](https://github.com/SupriyaMedankar)
40
- * Remove obsolete Sidebar code [publify#58](https://github.com/publify/publify/pull/58)
60
+ * Remove obsolete Sidebar code [publify_core#58](https://github.com/publify/publify_core/pull/58)
41
61
 
42
62
  ## 9.2.10 / 2023-01-08
43
63
 
@@ -93,7 +93,7 @@ class Admin::ArticlesController < Admin::BaseController
93
93
  end
94
94
 
95
95
  def auto_complete_for_article_keywords
96
- @items = Tag.select(:display_name).order(:display_name).map(&:display_name)
96
+ @items = Tag.order(:display_name).pluck(:display_name)
97
97
  render json: @items
98
98
  end
99
99
 
@@ -38,7 +38,7 @@ class Admin::PostTypesController < Admin::BaseController
38
38
  # Reset all Articles from the PostType we're destroying to the default PostType
39
39
  # Wrap it in a transaction for safety
40
40
  @post_type.transaction do
41
- Article.where(post_type: @post_type.permalink).each do |article|
41
+ Article.where(post_type: @post_type.permalink).find_each do |article|
42
42
  article.post_type = "read"
43
43
  article.save
44
44
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  class ArticlesController < ContentController
4
4
  before_action :login_required, only: [:preview, :preview_page]
5
- before_action :auto_discovery_feed, only: [:show, :index]
6
5
  before_action :verify_config
6
+ before_action :auto_discovery_feed, only: [:show, :index]
7
7
 
8
8
  layout :theme_layout, except: [:trackback]
9
9
 
@@ -201,7 +201,7 @@ class ArticlesController < ContentController
201
201
  case from
202
202
  when /^.*\.rss$/
203
203
  request.format = "rss"
204
- from = from.gsub(/\.rss/, "")
204
+ from = from.gsub(/\.rss$/, "")
205
205
  when /^.*\.atom$/
206
206
  request.format = "atom"
207
207
  from = from.gsub(/\.atom$/, "")
@@ -4,23 +4,24 @@ class SetupController < BaseController
4
4
  before_action :check_config
5
5
  layout "accounts"
6
6
 
7
- def index; end
7
+ def index
8
+ this_blog.blog_name = ""
9
+ @user = User.new
10
+ end
8
11
 
9
12
  def create
10
- this_blog.blog_name = params[:setting][:blog_name]
13
+ this_blog.blog_name = blog_params[:blog_name]
11
14
  this_blog.base_url = blog_base_url
12
15
 
13
- @user = User.new(login: "admin",
14
- email: params[:setting][:email],
15
- password: params[:setting][:password],
16
- text_filter_name: this_blog.text_filter,
17
- nickname: "Publify Admin")
16
+ @user = User.new(user_params.merge(login: "admin",
17
+ text_filter_name: this_blog.text_filter,
18
+ nickname: "Publify Admin"))
18
19
  @user.name = @user.login
19
20
 
20
- unless this_blog.save && @user.save
21
- redirect_to setup_url
22
- return
23
- end
21
+ return render :index unless this_blog.valid? && @user.valid?
22
+
23
+ this_blog.save!
24
+ @user.save!
24
25
 
25
26
  sign_in @user
26
27
 
@@ -36,6 +37,14 @@ class SetupController < BaseController
36
37
 
37
38
  private
38
39
 
40
+ def blog_params
41
+ params.require(:blog).permit(:blog_name)
42
+ end
43
+
44
+ def user_params
45
+ params.require(:user).permit(:email, :password)
46
+ end
47
+
39
48
  def create_first_post(user)
40
49
  this_blog.articles.build(title: I18n.t("setup.article.title"),
41
50
  author: user.login,
@@ -138,7 +138,7 @@ module BaseHelper
138
138
  v = v.chomp
139
139
  # trim the same number of spaces from the beginning of each line
140
140
  # this way plugins can indent nicely without making ugly source output
141
- spaces = /\A[ \t]*/.match(v)[0].gsub(/\t/, " ")
141
+ spaces = /\A[ \t]*/.match(v)[0].gsub("\t", " ")
142
142
  # add 2 spaces to line up with the assumed position of the surrounding tags
143
143
  v.gsub!(/^#{spaces}/, " ")
144
144
  end
@@ -174,8 +174,7 @@ class Article < Content
174
174
 
175
175
  if params[:title]
176
176
  req_params[:permalink] = CGI.escape(params[:title])
177
- article = published.find_by(req_params)
178
- return article if article
177
+ published.find_by(req_params)
179
178
  end
180
179
  end
181
180
 
data/app/models/note.rb CHANGED
@@ -44,7 +44,7 @@ class Note < Content
44
44
  end
45
45
 
46
46
  def html_postprocess(field, html)
47
- super(field, PublifyApp::Textfilter::Twitterfilter.filtertext(html))
47
+ super(field, PublifyCore::TextFilter::Twitterfilter.filtertext(html))
48
48
  end
49
49
 
50
50
  def truncate(message, length)
@@ -57,11 +57,9 @@ class ResourceUploader < CarrierWave::Uploader::Base
57
57
  end
58
58
 
59
59
  def check_content_type!(new_file)
60
- detected_type = if image? new_file
61
- file_content_content_type(new_file)
62
- else
63
- file_content_type(new_file)
64
- end
60
+ return unless image? new_file
61
+
62
+ detected_type = file_content_content_type(new_file)
65
63
  if detected_type != new_file.content_type
66
64
  raise CarrierWave::IntegrityError, "has MIME type mismatch"
67
65
  end
@@ -72,8 +70,4 @@ class ResourceUploader < CarrierWave::Uploader::Base
72
70
  def file_content_content_type(new_file)
73
71
  Marcel::MimeType.for Pathname.new(new_file.path)
74
72
  end
75
-
76
- def file_content_type(new_file)
77
- Marcel::MimeType.for Pathname.new(new_file.path), name: new_file.filename
78
- end
79
73
  end
@@ -5,7 +5,7 @@
5
5
  <%= image_tag(@reply['user']['profile_image_url'], class: 'alignleft', alt: @reply['user']['name']) %>
6
6
  <% end %>
7
7
  <strong><%= get_reply_context_url(@reply) %></strong>
8
- <p><%= nofollowify_links(PublifyApp::Textfilter::Twitterfilter.filtertext(@reply['text'])) %></p>
8
+ <p><%= nofollowify_links(PublifyCore::TextFilter::Twitterfilter.filtertext(@reply['text'])) %></p>
9
9
  <p>
10
10
  <small>
11
11
  <%= get_reply_context_twitter_link(@reply) %>
@@ -1,17 +1,48 @@
1
+ <div class="row">
2
+ <div class="col-md-8 col-md-offset-2" id="error-message-page">
3
+ <% if this_blog.errors.any? %>
4
+ <div id="error_explanation">
5
+ <h2><%= t("errors.template.header", model: 'blog', count: this_blog.errors.count) %></h2>
6
+ <p><%= t("errors.template.body") %></p>
7
+ <ul>
8
+ <% this_blog.errors.full_messages.each do |message| %>
9
+ <li><%= message %></li>
10
+ <% end %>
11
+ </ul>
12
+ </div>
13
+ <% end %>
14
+ <% if @user.errors.any? %>
15
+ <div id="error_explanation">
16
+ <h2><%= t("errors.template.header", model: 'blog', count: @user.errors.count) %></h2>
17
+ <p><%= t("errors.template.body") %></p>
18
+ <ul>
19
+ <% @user.errors.full_messages.each do |message| %>
20
+ <li><%= message %></li>
21
+ <% end %>
22
+ </ul>
23
+ </div>
24
+ <% end %>
25
+ </div>
26
+ </div>
27
+
1
28
  <%= form_tag action: 'index' do %>
2
29
  <div class='alert alert-info'>
3
30
  <small><%= t('.welcome_to_your_blog_setup', publify: link_to('Publify', 'https://publify.github.io/')) %></small>
4
31
  </div>
5
- <div class='form-group'>
6
- <%= text_field(:setting, :blog_name, class: 'form-control', placeholder: t('.blog_name')) %>
7
- </div>
8
- <div class='form-group'>
9
- <%= text_field(:setting, :email, class: 'form-control', placeholder: t('.your_mail')) %>
10
- </div>
11
- <div class='form-group'>
12
- <%= label_tag :setting_password, t('.password') %><br />
13
- <%= password_field(:setting, :password, class: 'form-control') %>
14
- </div>
32
+ <%= fields model: this_blog do |form| %>
33
+ <div class='form-group'>
34
+ <%= form.text_field(:blog_name, class: 'form-control', placeholder: t('.blog_name')) %>
35
+ </div>
36
+ <% end %>
37
+ <%= fields model: @user do |form| %>
38
+ <div class='form-group'>
39
+ <%= form.text_field(:email, class: 'form-control', placeholder: t('.your_mail')) %>
40
+ </div>
41
+ <div class='form-group'>
42
+ <%= form.label :password, t('.password') %><br>
43
+ <%= form.password_field(:password, class: 'form-control') %>
44
+ </div>
45
+ <% end %>
15
46
 
16
- <input type="submit" id="submit" class='btn btn-lg btn-success btn-block' value="<%= t('generic.save') %>" />
47
+ <input type="submit" id="submit" class='btn btn-lg btn-success btn-block' value="<%= t('generic.save') %>">
17
48
  <% end %>
data/db/seeds.rb CHANGED
@@ -13,9 +13,9 @@
13
13
  blog = Blog.first || Blog.create!
14
14
 
15
15
  unless blog.sidebars.any?
16
- PageSidebar.create!(active_position: 0, staged_position: 0, blog_id: blog.id)
17
- TagSidebar.create!(active_position: 1, blog_id: blog.id)
18
- ArchivesSidebar.create!(active_position: 2, blog_id: blog.id)
19
- StaticSidebar.create!(active_position: 3, blog_id: blog.id)
20
- MetaSidebar.create!(active_position: 4, blog_id: blog.id)
16
+ PageSidebar.create!(active_position: 0, staged_position: 0, blog: blog)
17
+ TagSidebar.create!(active_position: 1, blog: blog)
18
+ ArchivesSidebar.create!(active_position: 2, blog: blog)
19
+ StaticSidebar.create!(active_position: 3, blog: blog)
20
+ MetaSidebar.create!(active_position: 4, blog: blog)
21
21
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # FIXME: Replace with helpers and/or methods provided by Rails
4
+ module PublifyCore
5
+ module StringExt
6
+ ACCENTS = { %w(á à â ä ã Ã Ä Â À) => "a",
7
+ %w(é è ê ë Ë É È Ê) => "e",
8
+ %w(í ì î ï I Î Ì) => "i",
9
+ %w(ó ò ô ö õ Õ Ö Ô Ò) => "o",
10
+ ["œ"] => "oe",
11
+ ["ß"] => "ss",
12
+ %w(ú ù û ü U Û Ù) => "u",
13
+ %w(ç Ç) => "c" }.freeze
14
+
15
+ def to_permalink
16
+ string = self
17
+ ACCENTS.each do |key, value|
18
+ string = string.tr(key.join, value)
19
+ end
20
+ string = string.tr("'", "-")
21
+ string.gsub(/<[^>]*>/, "").to_url
22
+ end
23
+
24
+ # Returns a-string-with-dashes when passed 'a string with dashes'.
25
+ # All special chars are stripped in the process
26
+ def to_url
27
+ return if nil?
28
+
29
+ s = downcase.tr("\"'", "")
30
+ s = s.gsub(/\P{Word}/, " ")
31
+ s.strip.tr_s(" ", "-").tr(" ", "-").sub(/^$/, "-")
32
+ end
33
+
34
+ def to_title(item, settings, params)
35
+ TitleBuilder.new(self).build(item, settings, params)
36
+ end
37
+
38
+ # Strips any html markup from a string
39
+ TYPO_TAG_KEY = TYPO_ATTRIBUTE_KEY = /[\w:_-]+/.freeze
40
+ TYPO_ATTRIBUTE_VALUE = /(?:[A-Za-z0-9]+|(?:'[^']*?'|"[^"]*?"))/.freeze
41
+ TYPO_ATTRIBUTE = /(?:#{TYPO_ATTRIBUTE_KEY}(?:\s*=\s*#{TYPO_ATTRIBUTE_VALUE})?)/.freeze
42
+ TYPO_ATTRIBUTES = /(?:#{TYPO_ATTRIBUTE}(?:\s+#{TYPO_ATTRIBUTE})*)/.freeze
43
+ TAG =
44
+ %r{<[!/?\[]?(?:#{TYPO_TAG_KEY}|--)(?:\s+#{TYPO_ATTRIBUTES})?\s*(?:[!/?\]]+|--)?>}
45
+ .freeze
46
+ def strip_html
47
+ gsub(TAG, "").gsub(/\s+/, " ").strip
48
+ end
49
+ end
50
+ end
51
+
52
+ String.include PublifyCore::StringExt
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "text_filter_plugin"
4
+ require "commonmarker"
5
+
6
+ module PublifyCore::TextFilter
7
+ class Markdown < TextFilterPlugin::Markup
8
+ plugin_display_name "Markdown"
9
+ plugin_description "Markdown markup language from" \
10
+ ' <a href="http://daringfireball.com/">Daring Fireball</a>'
11
+
12
+ def self.help_text
13
+ <<~TXT
14
+ [Markdown](http://daringfireball.net/projects/markdown/) is a simple
15
+ text-to-HTML converter that turns common text idioms into HTML. The
16
+ [full syntax](http://daringfireball.net/projects/markdown/syntax) is
17
+ available from the author's site, but here's a short summary:
18
+
19
+ * **Paragraphs**: Start a new paragraph by skipping a line.
20
+ * **Italics**: Put text in *italics* by enclosing it in either * or
21
+ _: `*italics*` turns into *italics*.
22
+ * **Bold**: Put text in **bold** by enclosing it in two *s:
23
+ `**bold**` turns into **bold**.
24
+ * **Pre-formatted text**: Enclosing a short block of text in
25
+ backquotes (&#96;) displays it in a monospaced font and converts HTML
26
+ metacharacters so they display correctly. Example:
27
+ &#96;`<img src="foo"/>`&#96; displays as `<img src="foo"/>`. Also,
28
+ any paragraph indented 4 or more spaces is treated as pre-formatted
29
+ text.
30
+ * **Block quotes**: Any paragraph (or line) that starts with a `>` is
31
+ treated as a blockquote.
32
+ * **Hyperlinks**: You can create links like this:
33
+ `[amazon's web site](http://www.amazon.com)`. That produces
34
+ "[amazon's web site](http://www.amazon.com)".
35
+ * **Lists**: You can create numbered or bulleted lists by ending a
36
+ paragraph with a colon (:), skipping a line, and then using asterisks
37
+ (*, for bullets) or numbers (for numbered lists). See the
38
+ [Markdown syntax page](http://daringfireball.net/projects/markdown/syntax)
39
+ for examples.
40
+ * **Raw HTML**: Markdown will pass raw HTML through unchanged, so you
41
+ can use HTML's syntax whenever Markdown doesn't provide a reasonable
42
+ alternative.
43
+ TXT
44
+ end
45
+
46
+ def self.filtertext(text)
47
+ # FIXME: Workaround for <publify:foo> not being interpreted as an HTML tag.
48
+ escaped_macros = text.gsub(%r{(</?publify):}, '\1X')
49
+ html = CommonMarker.render_html(escaped_macros, :UNSAFE)
50
+ html.gsub(%r{(</?publify)X}, '\1:').strip
51
+ end
52
+ end
53
+ end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "text_filter_plugin"
4
- require "publify_textfilter_markdown"
4
+ require "publify_core/text_filter/markdown"
5
5
 
6
- module PublifyTextfilter
7
- class MarkdownSmartquotes < PublifyApp::Textfilter::Markdown
6
+ module PublifyCore::TextFilter
7
+ class MarkdownSmartquotes < PublifyCore::TextFilter::Markdown
8
8
  plugin_display_name "Markdown with smart quotes"
9
9
  plugin_description "Markdown markup language from" \
10
10
  ' <a href="http://daringfireball.com/">Daring Fireball</a>' \
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "text_filter_plugin"
4
+
5
+ module PublifyCore::TextFilter
6
+ class None < TextFilterPlugin::Markup
7
+ plugin_display_name "None"
8
+ plugin_description "Raw HTML only"
9
+
10
+ def self.filtertext(text)
11
+ text
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubypants"
4
+
5
+ module PublifyCore::TextFilter
6
+ class Smartypants < TextFilterPlugin::PostProcess
7
+ plugin_display_name "Smartypants"
8
+ plugin_description "Converts HTML to use typographically correct quotes and dashes"
9
+
10
+ def self.filtertext(text)
11
+ RubyPants.new(text).to_html
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "text_filter_plugin"
4
+ require "html/pipeline"
5
+ require "html/pipeline/hashtag/hashtag_filter"
6
+
7
+ module PublifyCore::TextFilter
8
+ class Twitterfilter < TextFilterPlugin::PostProcess
9
+ plugin_display_name "Twitter Filter"
10
+ plugin_description "Convert hashtags and mentions to links"
11
+
12
+ class TwitterHashtagFilter < HTML::Pipeline::HashtagFilter
13
+ def initialize(text)
14
+ super(text,
15
+ tag_url: "https://twitter.com/search?q=%%23%<tag>s&src=tren&mode=realtime",
16
+ tag_link_attr: "")
17
+ end
18
+ end
19
+
20
+ class TwitterMentionFilter < HTML::Pipeline::MentionFilter
21
+ def initialize(text)
22
+ super(text, base_url: "https://twitter.com")
23
+ end
24
+
25
+ # Override base mentions finder, treating @mention just like any other @foo.
26
+ def self.mentioned_logins_in(text, username_pattern = UsernamePattern)
27
+ text.gsub MentionPatterns[username_pattern] do |match|
28
+ login = Regexp.last_match(1)
29
+ yield match, login, false
30
+ end
31
+ end
32
+
33
+ # Override base link creator, removing the class
34
+ def link_to_mentioned_user(login)
35
+ result[:mentioned_usernames] |= [login]
36
+
37
+ url = base_url.dup
38
+ url << "/" unless %r{[/~]\z}.match?(url)
39
+
40
+ "<a href='#{url << login}'>" \
41
+ "@#{login}" \
42
+ "</a>"
43
+ end
44
+ end
45
+
46
+ def self.filtertext(text)
47
+ # First, autolink
48
+ helper = PublifyCore::ContentTextHelpers.new
49
+ text = helper.auto_link(text)
50
+
51
+ text = TwitterHashtagFilter.new(text).call
52
+ TwitterMentionFilter.new(text).call.to_s
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PublifyCore
4
- VERSION = "10.0.0"
4
+ VERSION = "10.0.1"
5
5
  end
data/lib/publify_core.rb CHANGED
@@ -8,6 +8,12 @@ require "publify_core/version"
8
8
  require "publify_core/engine"
9
9
  require "publify_core/lang"
10
10
  require "publify_core/content_text_helpers"
11
+ require "publify_core/text_filter/none"
12
+ require "publify_core/text_filter/markdown"
13
+ require "publify_core/text_filter/markdown_smartquotes"
14
+ require "publify_core/text_filter/smartypants"
15
+ require "publify_core/text_filter/twitterfilter"
16
+ require "publify_core/string_ext"
11
17
 
12
18
  require "carrierwave"
13
19
  require "jquery-rails"
@@ -20,17 +26,11 @@ require "sassc-rails"
20
26
 
21
27
  require "email_notify"
22
28
  require "publify_guid"
23
- require "publify_textfilter_none"
24
- require "publify_textfilter_markdown"
25
- require "publify_textfilter_markdown_smartquotes"
26
- require "publify_textfilter_smartypants"
27
- require "publify_textfilter_twitterfilter"
28
29
  require "publify_time"
29
30
  require "sidebar_registry"
30
31
  require "spam_protection"
31
32
  require "text_filter_plugin"
32
33
  require "theme"
33
- require "transforms"
34
34
 
35
35
  module PublifyCore
36
36
  Theme.register_themes File.join(Engine.root, "themes")
@@ -13,10 +13,8 @@ class TextFilterPlugin
13
13
  def self.inherited(sub)
14
14
  super
15
15
 
16
- if sub.to_s.start_with?("Plugin", "PublifyTextfilter", "PublifyApp::Textfilter")
17
- name = sub.short_name
18
- @@filter_map[name] = sub
19
- end
16
+ name = sub.short_name
17
+ @@filter_map[name] = sub
20
18
  end
21
19
 
22
20
  def self.filter_map
@@ -116,34 +114,40 @@ class TextFilterPlugin
116
114
  def self.logger
117
115
  @logger ||= ::Rails.logger || Logger.new($stdout)
118
116
  end
117
+
118
+ def self.abstract_filter!
119
+ @@filter_map.delete short_name
120
+ end
119
121
  end
120
122
 
121
123
  class TextFilterPlugin::PostProcess < TextFilterPlugin
124
+ abstract_filter!
125
+
122
126
  def self.filter_type
123
127
  "postprocess"
124
128
  end
125
129
  end
126
130
 
127
- class TextFilterPlugin::Macro < TextFilterPlugin
131
+ module TextFilterPlugin::MacroMethods
128
132
  # Utility function -- hand it a XML string like <a href="foo" title="bar">
129
133
  # and it'll give you back { "href" => "foo", "title" => "bar" }
130
- def self.attributes_parse(string)
134
+ def attributes_parse(string)
131
135
  attributes = {}
132
136
 
133
137
  string.gsub(/([^ =]+="[^"]*")/) do |match|
134
- key, value = match.split(/=/, 2)
138
+ key, value = match.split("=", 2)
135
139
  attributes[key] = value.delete('"')
136
140
  end
137
141
 
138
142
  string.gsub(/([^ =]+='[^']*')/) do |match|
139
- key, value = match.split(/=/, 2)
143
+ key, value = match.split("=", 2)
140
144
  attributes[key] = value.delete("'")
141
145
  end
142
146
 
143
147
  attributes
144
148
  end
145
149
 
146
- def self.filtertext(text)
150
+ def filtertext(text)
147
151
  regex1 = %r{<publify:#{short_name}(?:[ \t][^>]*)?/>}
148
152
  regex2 = %r{<publify:#{short_name}([ \t][^>]*)?>(.*?)</publify:#{short_name}>}m
149
153
 
@@ -157,19 +161,27 @@ class TextFilterPlugin::Macro < TextFilterPlugin
157
161
  end
158
162
  end
159
163
 
160
- class TextFilterPlugin::MacroPre < TextFilterPlugin::Macro
164
+ class TextFilterPlugin::MacroPre < TextFilterPlugin
165
+ abstract_filter!
166
+ extend TextFilterPlugin::MacroMethods
167
+
161
168
  def self.filter_type
162
169
  "macropre"
163
170
  end
164
171
  end
165
172
 
166
- class TextFilterPlugin::MacroPost < TextFilterPlugin::Macro
173
+ class TextFilterPlugin::MacroPost < TextFilterPlugin
174
+ abstract_filter!
175
+ extend TextFilterPlugin::MacroMethods
176
+
167
177
  def self.filter_type
168
178
  "macropost"
169
179
  end
170
180
  end
171
181
 
172
182
  class TextFilterPlugin::Markup < TextFilterPlugin
183
+ abstract_filter!
184
+
173
185
  def self.filter_type
174
186
  "markup"
175
187
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: publify_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.0.0
4
+ version: 10.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matijs van Zuijlen
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-06-25 00:00:00.000000000 Z
14
+ date: 2023-10-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: aasm
@@ -61,14 +61,14 @@ dependencies:
61
61
  requirements:
62
62
  - - "~>"
63
63
  - !ruby/object:Gem::Version
64
- version: 2.2.1
64
+ version: '3.0'
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - "~>"
70
70
  - !ruby/object:Gem::Version
71
- version: 2.2.1
71
+ version: '3.0'
72
72
  - !ruby/object:Gem::Dependency
73
73
  name: commonmarker
74
74
  requirement: !ruby/object:Gem::Requirement
@@ -191,16 +191,22 @@ dependencies:
191
191
  name: jquery-rails
192
192
  requirement: !ruby/object:Gem::Requirement
193
193
  requirements:
194
- - - "~>"
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '4.5'
197
+ - - "<"
195
198
  - !ruby/object:Gem::Version
196
- version: 4.5.0
199
+ version: '4.7'
197
200
  type: :runtime
198
201
  prerelease: false
199
202
  version_requirements: !ruby/object:Gem::Requirement
200
203
  requirements:
201
- - - "~>"
204
+ - - ">="
202
205
  - !ruby/object:Gem::Version
203
- version: 4.5.0
206
+ version: '4.5'
207
+ - - "<"
208
+ - !ruby/object:Gem::Version
209
+ version: '4.7'
204
210
  - !ruby/object:Gem::Dependency
205
211
  name: jquery-ui-rails
206
212
  requirement: !ruby/object:Gem::Requirement
@@ -539,70 +545,84 @@ dependencies:
539
545
  requirements:
540
546
  - - "~>"
541
547
  - !ruby/object:Gem::Version
542
- version: 1.52.0
548
+ version: 1.57.1
549
+ type: :development
550
+ prerelease: false
551
+ version_requirements: !ruby/object:Gem::Requirement
552
+ requirements:
553
+ - - "~>"
554
+ - !ruby/object:Gem::Version
555
+ version: 1.57.1
556
+ - !ruby/object:Gem::Dependency
557
+ name: rubocop-capybara
558
+ requirement: !ruby/object:Gem::Requirement
559
+ requirements:
560
+ - - "~>"
561
+ - !ruby/object:Gem::Version
562
+ version: 2.19.0
543
563
  type: :development
544
564
  prerelease: false
545
565
  version_requirements: !ruby/object:Gem::Requirement
546
566
  requirements:
547
567
  - - "~>"
548
568
  - !ruby/object:Gem::Version
549
- version: 1.52.0
569
+ version: 2.19.0
550
570
  - !ruby/object:Gem::Dependency
551
571
  name: rubocop-factory_bot
552
572
  requirement: !ruby/object:Gem::Requirement
553
573
  requirements:
554
574
  - - "~>"
555
575
  - !ruby/object:Gem::Version
556
- version: 2.23.1
576
+ version: 2.24.0
557
577
  type: :development
558
578
  prerelease: false
559
579
  version_requirements: !ruby/object:Gem::Requirement
560
580
  requirements:
561
581
  - - "~>"
562
582
  - !ruby/object:Gem::Version
563
- version: 2.23.1
583
+ version: 2.24.0
564
584
  - !ruby/object:Gem::Dependency
565
585
  name: rubocop-performance
566
586
  requirement: !ruby/object:Gem::Requirement
567
587
  requirements:
568
588
  - - "~>"
569
589
  - !ruby/object:Gem::Version
570
- version: 1.18.0
590
+ version: 1.19.0
571
591
  type: :development
572
592
  prerelease: false
573
593
  version_requirements: !ruby/object:Gem::Requirement
574
594
  requirements:
575
595
  - - "~>"
576
596
  - !ruby/object:Gem::Version
577
- version: 1.18.0
597
+ version: 1.19.0
578
598
  - !ruby/object:Gem::Dependency
579
599
  name: rubocop-rails
580
600
  requirement: !ruby/object:Gem::Requirement
581
601
  requirements:
582
602
  - - "~>"
583
603
  - !ruby/object:Gem::Version
584
- version: 2.20.2
604
+ version: 2.21.1
585
605
  type: :development
586
606
  prerelease: false
587
607
  version_requirements: !ruby/object:Gem::Requirement
588
608
  requirements:
589
609
  - - "~>"
590
610
  - !ruby/object:Gem::Version
591
- version: 2.20.2
611
+ version: 2.21.1
592
612
  - !ruby/object:Gem::Dependency
593
613
  name: rubocop-rspec
594
614
  requirement: !ruby/object:Gem::Requirement
595
615
  requirements:
596
616
  - - "~>"
597
617
  - !ruby/object:Gem::Version
598
- version: 2.22.0
618
+ version: 2.24.1
599
619
  type: :development
600
620
  prerelease: false
601
621
  version_requirements: !ruby/object:Gem::Requirement
602
622
  requirements:
603
623
  - - "~>"
604
624
  - !ruby/object:Gem::Version
605
- version: 2.22.0
625
+ version: 2.24.1
606
626
  - !ruby/object:Gem::Dependency
607
627
  name: shoulda-matchers
608
628
  requirement: !ruby/object:Gem::Requirement
@@ -1103,6 +1123,7 @@ files:
1103
1123
  - lib/publify_core/content_text_helpers.rb
1104
1124
  - lib/publify_core/engine.rb
1105
1125
  - lib/publify_core/lang.rb
1126
+ - lib/publify_core/string_ext.rb
1106
1127
  - lib/publify_core/testing_support/dns_mock.rb
1107
1128
  - lib/publify_core/testing_support/factories/articles.rb
1108
1129
  - lib/publify_core/testing_support/factories/blogs.rb
@@ -1127,14 +1148,14 @@ files:
1127
1148
  - lib/publify_core/testing_support/fixtures/testfile.png
1128
1149
  - lib/publify_core/testing_support/fixtures/testfile.txt
1129
1150
  - lib/publify_core/testing_support/upload_fixtures.rb
1151
+ - lib/publify_core/text_filter/markdown.rb
1152
+ - lib/publify_core/text_filter/markdown_smartquotes.rb
1153
+ - lib/publify_core/text_filter/none.rb
1154
+ - lib/publify_core/text_filter/smartypants.rb
1155
+ - lib/publify_core/text_filter/twitterfilter.rb
1130
1156
  - lib/publify_core/version.rb
1131
1157
  - lib/publify_guid.rb
1132
1158
  - lib/publify_plugins.rb
1133
- - lib/publify_textfilter_markdown.rb
1134
- - lib/publify_textfilter_markdown_smartquotes.rb
1135
- - lib/publify_textfilter_none.rb
1136
- - lib/publify_textfilter_smartypants.rb
1137
- - lib/publify_textfilter_twitterfilter.rb
1138
1159
  - lib/publify_time.rb
1139
1160
  - lib/sidebar_field.rb
1140
1161
  - lib/sidebar_registry.rb
@@ -1143,7 +1164,6 @@ files:
1143
1164
  - lib/tasks/publify_core_tasks.rake
1144
1165
  - lib/text_filter_plugin.rb
1145
1166
  - lib/theme.rb
1146
- - lib/transforms.rb
1147
1167
  - themes/plain/about.markdown
1148
1168
  - themes/plain/javascripts/theme.js
1149
1169
  - themes/plain/preview.png
@@ -1168,7 +1188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1168
1188
  - !ruby/object:Gem::Version
1169
1189
  version: '0'
1170
1190
  requirements: []
1171
- rubygems_version: 3.4.14
1191
+ rubygems_version: 3.4.20
1172
1192
  signing_key:
1173
1193
  specification_version: 4
1174
1194
  summary: Core engine for the Publify blogging system.
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "text_filter_plugin"
4
- require "commonmarker"
5
-
6
- # TODO: Move to a different namespace
7
- class PublifyApp
8
- class Textfilter
9
- class Markdown < TextFilterPlugin::Markup
10
- plugin_display_name "Markdown"
11
- plugin_description "Markdown markup language from" \
12
- ' <a href="http://daringfireball.com/">Daring Fireball</a>'
13
-
14
- def self.help_text
15
- <<~TXT
16
- [Markdown](http://daringfireball.net/projects/markdown/) is a simple
17
- text-to-HTML converter that turns common text idioms into HTML. The
18
- [full syntax](http://daringfireball.net/projects/markdown/syntax) is
19
- available from the author's site, but here's a short summary:
20
-
21
- * **Paragraphs**: Start a new paragraph by skipping a line.
22
- * **Italics**: Put text in *italics* by enclosing it in either * or
23
- _: `*italics*` turns into *italics*.
24
- * **Bold**: Put text in **bold** by enclosing it in two *s:
25
- `**bold**` turns into **bold**.
26
- * **Pre-formatted text**: Enclosing a short block of text in
27
- backquotes (&#96;) displays it in a monospaced font and converts HTML
28
- metacharacters so they display correctly. Example:
29
- &#96;`<img src="foo"/>`&#96; displays as `<img src="foo"/>`. Also,
30
- any paragraph indented 4 or more spaces is treated as pre-formatted
31
- text.
32
- * **Block quotes**: Any paragraph (or line) that starts with a `>` is
33
- treated as a blockquote.
34
- * **Hyperlinks**: You can create links like this:
35
- `[amazon's web site](http://www.amazon.com)`. That produces
36
- "[amazon's web site](http://www.amazon.com)".
37
- * **Lists**: You can create numbered or bulleted lists by ending a
38
- paragraph with a colon (:), skipping a line, and then using asterisks
39
- (*, for bullets) or numbers (for numbered lists). See the
40
- [Markdown syntax page](http://daringfireball.net/projects/markdown/syntax)
41
- for examples.
42
- * **Raw HTML**: Markdown will pass raw HTML through unchanged, so you
43
- can use HTML's syntax whenever Markdown doesn't provide a reasonable
44
- alternative.
45
- TXT
46
- end
47
-
48
- def self.filtertext(text)
49
- # FIXME: Workaround for <publify:foo> not being interpreted as an HTML tag.
50
- escaped_macros = text.gsub(%r{(</?publify):}, '\1X')
51
- html = CommonMarker.render_html(escaped_macros, :UNSAFE)
52
- html.gsub(%r{(</?publify)X}, '\1:').strip
53
- end
54
- end
55
- end
56
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "text_filter_plugin"
4
-
5
- class PublifyApp
6
- class Textfilter
7
- class None < TextFilterPlugin::Markup
8
- plugin_display_name "None"
9
- plugin_description "Raw HTML only"
10
-
11
- def self.filtertext(text)
12
- text
13
- end
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rubypants"
4
-
5
- class PublifyApp
6
- class Textfilter
7
- class Smartypants < TextFilterPlugin::PostProcess
8
- plugin_display_name "Smartypants"
9
- plugin_description "Converts HTML to use typographically correct quotes and dashes"
10
-
11
- def self.filtertext(text)
12
- RubyPants.new(text).to_html
13
- end
14
- end
15
- end
16
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "text_filter_plugin"
4
- require "html/pipeline"
5
- require "html/pipeline/hashtag/hashtag_filter"
6
-
7
- class PublifyApp
8
- class Textfilter
9
- class Twitterfilter < TextFilterPlugin::PostProcess
10
- plugin_display_name "HTML Filter"
11
- plugin_description "Strip HTML tags"
12
-
13
- class TwitterHashtagFilter < HTML::Pipeline::HashtagFilter
14
- def initialize(text)
15
- super(text,
16
- tag_url: "https://twitter.com/search?q=%%23%<tag>s&src=tren&mode=realtime",
17
- tag_link_attr: "")
18
- end
19
- end
20
-
21
- class TwitterMentionFilter < HTML::Pipeline::MentionFilter
22
- def initialize(text)
23
- super(text, base_url: "https://twitter.com")
24
- end
25
-
26
- # Override base mentions finder, treating @mention just like any other @foo.
27
- def self.mentioned_logins_in(text, username_pattern = UsernamePattern)
28
- text.gsub MentionPatterns[username_pattern] do |match|
29
- login = Regexp.last_match(1)
30
- yield match, login, false
31
- end
32
- end
33
-
34
- # Override base link creator, removing the class
35
- def link_to_mentioned_user(login)
36
- result[:mentioned_usernames] |= [login]
37
-
38
- url = base_url.dup
39
- url << "/" unless %r{[/~]\z}.match?(url)
40
-
41
- "<a href='#{url << login}'>" \
42
- "@#{login}" \
43
- "</a>"
44
- end
45
- end
46
-
47
- def self.filtertext(text)
48
- # First, autolink
49
- helper = PublifyCore::ContentTextHelpers.new
50
- text = helper.auto_link(text)
51
-
52
- text = TwitterHashtagFilter.new(text).call
53
- TwitterMentionFilter.new(text).call.to_s
54
- end
55
- end
56
- end
57
- end
data/lib/transforms.rb DELETED
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # FIXME: Replace with helpers and/or methods provided by Rails
4
- class String
5
- ACCENTS = { %w(á à â ä ã Ã Ä Â À) => "a",
6
- %w(é è ê ë Ë É È Ê) => "e",
7
- %w(í ì î ï I Î Ì) => "i",
8
- %w(ó ò ô ö õ Õ Ö Ô Ò) => "o",
9
- ["œ"] => "oe",
10
- ["ß"] => "ss",
11
- %w(ú ù û ü U Û Ù) => "u",
12
- %w(ç Ç) => "c" }.freeze
13
-
14
- def to_permalink
15
- string = self
16
- ACCENTS.each do |key, value|
17
- string = string.tr(key.join, value)
18
- end
19
- string = string.tr("'", "-")
20
- string.gsub(/<[^>]*>/, "").to_url
21
- end
22
-
23
- # Returns a-string-with-dashes when passed 'a string with dashes'.
24
- # All special chars are stripped in the process
25
- def to_url
26
- return if nil?
27
-
28
- s = downcase.tr("\"'", "")
29
- s = s.gsub(/\P{Word}/, " ")
30
- s.strip.tr_s(" ", "-").tr(" ", "-").sub(/^$/, "-")
31
- end
32
-
33
- def to_title(item, settings, params)
34
- TitleBuilder.new(self).build(item, settings, params)
35
- end
36
-
37
- # Strips any html markup from a string
38
- TYPO_TAG_KEY = TYPO_ATTRIBUTE_KEY = /[\w:_-]+/.freeze
39
- TYPO_ATTRIBUTE_VALUE = /(?:[A-Za-z0-9]+|(?:'[^']*?'|"[^"]*?"))/.freeze
40
- TYPO_ATTRIBUTE = /(?:#{TYPO_ATTRIBUTE_KEY}(?:\s*=\s*#{TYPO_ATTRIBUTE_VALUE})?)/.freeze
41
- TYPO_ATTRIBUTES = /(?:#{TYPO_ATTRIBUTE}(?:\s+#{TYPO_ATTRIBUTE})*)/.freeze
42
- TAG =
43
- %r{<[!/?\[]?(?:#{TYPO_TAG_KEY}|--)(?:\s+#{TYPO_ATTRIBUTES})?\s*(?:[!/?\]]+|--)?>}.freeze
44
- def strip_html
45
- gsub(TAG, "").gsub(/\s+/, " ").strip
46
- end
47
- end