publify_core 10.0.0 → 10.0.1

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.

Potentially problematic release.


This version of publify_core might be problematic. Click here for more details.

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