scribo 1.0.38
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +93 -0
- data/Rakefile +40 -0
- data/app/assets/config/scribo_manifest.js +2 -0
- data/app/assets/javascripts/scribo/scribo.js +1 -0
- data/app/assets/stylesheets/scribo/scribo.css +1 -0
- data/app/controllers/concerns/maintenance_standards.rb +24 -0
- data/app/controllers/scribo/admin/sites/contents_controller.rb +86 -0
- data/app/controllers/scribo/admin/sites_controller.rb +61 -0
- data/app/controllers/scribo/api/sites_controller.rb +23 -0
- data/app/controllers/scribo/application_admin_controller.rb +11 -0
- data/app/controllers/scribo/application_controller.rb +6 -0
- data/app/controllers/scribo/contents_controller.rb +20 -0
- data/app/drops/scribo/action_dispatch/request_drop.rb +15 -0
- data/app/drops/scribo/active_model/errors_drop.rb +16 -0
- data/app/drops/scribo/application_drop.rb +9 -0
- data/app/drops/scribo/array_drop.rb +13 -0
- data/app/drops/scribo/content_drop.rb +73 -0
- data/app/drops/scribo/data_drop.rb +35 -0
- data/app/drops/scribo/form_drop.rb +26 -0
- data/app/drops/scribo/include_drop.rb +13 -0
- data/app/drops/scribo/paginator_drop.rb +73 -0
- data/app/drops/scribo/site_drop.rb +83 -0
- data/app/helpers/scribo/application_helper.rb +13 -0
- data/app/jobs/scribo/application_job.rb +6 -0
- data/app/models/scribo/application_record.rb +11 -0
- data/app/models/scribo/content.rb +378 -0
- data/app/models/scribo/site.rb +161 -0
- data/app/services/scribo/application_service.rb +9 -0
- data/app/services/scribo/content_find_service.rb +69 -0
- data/app/services/scribo/content_render_service.rb +127 -0
- data/app/services/scribo/site_export_service.rb +41 -0
- data/app/services/scribo/site_find_service.rb +26 -0
- data/app/services/scribo/site_import_service.rb +96 -0
- data/app/views/layouts/scribo.html.slim +1 -0
- data/app/views/scribo/admin/sites/_create_sites.html.slim +22 -0
- data/app/views/scribo/admin/sites/_sites.html.slim +18 -0
- data/app/views/scribo/admin/sites/contents/_form.html.slim +17 -0
- data/app/views/scribo/admin/sites/contents/create.json.jbuilder +11 -0
- data/app/views/scribo/admin/sites/contents/edit.html.slim +2 -0
- data/app/views/scribo/admin/sites/contents/edit.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/index.html.slim +1 -0
- data/app/views/scribo/admin/sites/contents/move.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/rename.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/contents/upload.json.jbuilder +9 -0
- data/app/views/scribo/admin/sites/import.json.jbuilder +4 -0
- data/app/views/scribo/admin/sites/index.html.slim +7 -0
- data/app/views/scribo/shared/_entry.html.slim +17 -0
- data/app/views/scribo/shared/_ide.html.slim +14 -0
- data/app/views/scribo/shared/_tree-view.html.slim +32 -0
- data/config/locales/en.yml +39 -0
- data/config/routes.rb +35 -0
- data/db/migrate/20200123095630_initial_scribo.rb +34 -0
- data/db/migrate/20220919124119_add_ancestry_to_scribo_contents.rb +13 -0
- data/db/migrate/20220919124749_remove_parent_id_from_scribo_contents.rb +8 -0
- data/lib/scribo/action_controller_helpers.rb +51 -0
- data/lib/scribo/action_controller_renderers.rb +71 -0
- data/lib/scribo/action_view_helpers.rb +17 -0
- data/lib/scribo/active_record_helpers.rb +11 -0
- data/lib/scribo/configuration.rb +97 -0
- data/lib/scribo/engine.rb +24 -0
- data/lib/scribo/i18n_store.rb +100 -0
- data/lib/scribo/liquid/filters/jekyll_filters.rb +94 -0
- data/lib/scribo/liquid/filters/markdownify.rb +11 -0
- data/lib/scribo/liquid/filters/url_filters.rb +76 -0
- data/lib/scribo/liquid/parser.rb +32 -0
- data/lib/scribo/liquid/tags/application_assets_tag.rb +14 -0
- data/lib/scribo/liquid/tags/application_js_tag.rb +16 -0
- data/lib/scribo/liquid/tags/asset_tag.rb +56 -0
- data/lib/scribo/liquid/tags/button_tag.rb +24 -0
- data/lib/scribo/liquid/tags/check_box_tag.rb +31 -0
- data/lib/scribo/liquid/tags/csrf_meta_tags_tag.rb +16 -0
- data/lib/scribo/liquid/tags/date_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/editable_url_tag.rb +19 -0
- data/lib/scribo/liquid/tags/email_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/feed_meta_tag.rb +22 -0
- data/lib/scribo/liquid/tags/field_error_tag.rb +26 -0
- data/lib/scribo/liquid/tags/fields_for_tag.rb +82 -0
- data/lib/scribo/liquid/tags/form_tag.rb +57 -0
- data/lib/scribo/liquid/tags/google_analytics_javascript_tag.rb +30 -0
- data/lib/scribo/liquid/tags/google_tag_manager_javascript_tag.rb +28 -0
- data/lib/scribo/liquid/tags/hidden_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/highlight_tag.rb +106 -0
- data/lib/scribo/liquid/tags/include_tag.rb +28 -0
- data/lib/scribo/liquid/tags/label_tag.rb +24 -0
- data/lib/scribo/liquid/tags/number_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/options_for_select.rb +36 -0
- data/lib/scribo/liquid/tags/password_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/search_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/search_tag.rb +29 -0
- data/lib/scribo/liquid/tags/select_tag.rb +22 -0
- data/lib/scribo/liquid/tags/seo_tag.rb +35 -0
- data/lib/scribo/liquid/tags/set_session.rb +19 -0
- data/lib/scribo/liquid/tags/telephone_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/text_field_tag.rb +35 -0
- data/lib/scribo/liquid/tags/textarea_tag.rb +28 -0
- data/lib/scribo/liquid/tags/time_field_tag.rb +23 -0
- data/lib/scribo/liquid/tags/url_field_tag.rb +23 -0
- data/lib/scribo/preamble.rb +89 -0
- data/lib/scribo/sassc/importer.rb +72 -0
- data/lib/scribo/utility.rb +94 -0
- data/lib/scribo/version.rb +5 -0
- data/lib/scribo.rb +59 -0
- data/lib/tasks/scribo_tasks.rake +28 -0
- metadata +498 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class HighlightBlock < Liquid::Block
|
|
4
|
+
include Liquid::StandardFilters
|
|
5
|
+
|
|
6
|
+
# The regular expression syntax checker. Start with the language specifier.
|
|
7
|
+
# Follow that by zero or more space separated options that take one of three
|
|
8
|
+
# forms: name, name=value, or name="<quoted list>"
|
|
9
|
+
#
|
|
10
|
+
# <quoted list> is a space-separated list of numbers
|
|
11
|
+
SYNTAX = /^([a-zA-Z0-9.+#_-]+)((\s+\w+(=(\w+|"([0-9]+\s)*[0-9]+"))?)*)$/.freeze
|
|
12
|
+
|
|
13
|
+
def initialize(tag_name, markup, tokens)
|
|
14
|
+
super
|
|
15
|
+
if markup.strip =~ SYNTAX
|
|
16
|
+
@lang = Regexp.last_match(1).downcase
|
|
17
|
+
@highlight_options = parse_options(Regexp.last_match(2))
|
|
18
|
+
else
|
|
19
|
+
raise SyntaxError, <<~MSG
|
|
20
|
+
Syntax Error in tag 'highlight' while parsing the following markup:
|
|
21
|
+
|
|
22
|
+
#{markup}
|
|
23
|
+
|
|
24
|
+
Valid syntax: highlight <lang> [linenos]
|
|
25
|
+
MSG
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
LEADING_OR_TRAILING_LINE_TERMINATORS = /\A(\n|\r)+|(\n|\r)+\z/.freeze
|
|
30
|
+
|
|
31
|
+
def render(context)
|
|
32
|
+
prefix = context['highlighter_prefix'] || ''
|
|
33
|
+
suffix = context['highlighter_suffix'] || ''
|
|
34
|
+
code = super.to_s.gsub(LEADING_OR_TRAILING_LINE_TERMINATORS, '')
|
|
35
|
+
|
|
36
|
+
output =
|
|
37
|
+
case context.registers[:site]&.highlighter
|
|
38
|
+
when 'rouge'
|
|
39
|
+
render_rouge(code)
|
|
40
|
+
when 'pygments'
|
|
41
|
+
render_pygments(code, context)
|
|
42
|
+
else
|
|
43
|
+
render_codehighlighter(code)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
rendered_output = add_code_tag(output)
|
|
47
|
+
prefix + rendered_output + suffix
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
OPTIONS_REGEX = /(?:\w="[^"]*"|\w=\w|\w)+/.freeze
|
|
53
|
+
|
|
54
|
+
def parse_options(input)
|
|
55
|
+
options = {}
|
|
56
|
+
return options if input.empty?
|
|
57
|
+
|
|
58
|
+
# Split along 3 possible forms -- key="<quoted list>", key=value, or key
|
|
59
|
+
input.scan(OPTIONS_REGEX) do |opt|
|
|
60
|
+
key, value = opt.split('=')
|
|
61
|
+
# If a quoted list, convert to array
|
|
62
|
+
if value&.include?('"')
|
|
63
|
+
value.delete!('"')
|
|
64
|
+
value = value.split
|
|
65
|
+
end
|
|
66
|
+
options[key.to_sym] = value || true
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
options[:linenos] = 'inline' if options[:linenos] == true
|
|
70
|
+
options
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def render_pygments(code, _context)
|
|
74
|
+
Scribo.logger.warn 'Warning: Highlight Tag no longer supports rendering with Pygments. Using the default highlighter, Rouge, instead.'
|
|
75
|
+
render_rouge(code)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def render_rouge(code)
|
|
79
|
+
require 'rouge'
|
|
80
|
+
formatter = ::Rouge::Formatters::HTMLLegacy.new(
|
|
81
|
+
line_numbers: @highlight_options[:linenos],
|
|
82
|
+
wrap: false,
|
|
83
|
+
css_class: 'highlight',
|
|
84
|
+
gutter_class: 'gutter',
|
|
85
|
+
code_class: 'code'
|
|
86
|
+
)
|
|
87
|
+
lexer = ::Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
|
|
88
|
+
formatter.format(lexer.lex(code))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def render_codehighlighter(code)
|
|
92
|
+
Scribo.logger.warn 'Warning: Highlight Tag no longer supports rendering with Pygments. Using the default highlighter, Rouge, instead.'
|
|
93
|
+
render_rouge(code)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def add_code_tag(code)
|
|
97
|
+
code_attributes = [
|
|
98
|
+
"class=\"language-#{@lang.to_s.tr('+', '-')}\"",
|
|
99
|
+
"data-lang=\"#{@lang}\""
|
|
100
|
+
].join(' ')
|
|
101
|
+
"<figure class=\"highlight\"><pre><code #{code_attributes}>"\
|
|
102
|
+
"#{code.chomp}</code></pre></figure>"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
Liquid::Template.register_tag('highlight', HighlightBlock)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Include other published content
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%include 'navigation'}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%include 'navigation' title:"Menu"}
|
|
10
|
+
#
|
|
11
|
+
# This allows you pass variables to the included content, which will only available there
|
|
12
|
+
#
|
|
13
|
+
class IncludeTag < LiquidumTag
|
|
14
|
+
def render(context)
|
|
15
|
+
super
|
|
16
|
+
|
|
17
|
+
content = context.registers['file_system'].read_template_file(argv1)
|
|
18
|
+
|
|
19
|
+
result = ''
|
|
20
|
+
context.stack do
|
|
21
|
+
context['include'] = Scribo::IncludeDrop.new(attr_args.deep_stringify_keys)
|
|
22
|
+
result += Liquidum.render(content, context: context, registers: context.registers)
|
|
23
|
+
end
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Liquid::Template.register_tag('include', IncludeTag)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a text_field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%label for:"name"%}Name:{%endlabel%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%label name%}Name:{%endlabel%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
class LabelTag < LiquidumBlock
|
|
14
|
+
def render(context)
|
|
15
|
+
super
|
|
16
|
+
|
|
17
|
+
@form_model = lookup(context, 'form.model')
|
|
18
|
+
@form_class_name = lookup(context, 'form.class_name')
|
|
19
|
+
|
|
20
|
+
%[<label] + attr_str(:for, arg(:for), input(:id, argv1)) + %[>] + render_body + %[</label>]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Liquid::Template.register_tag('label', LabelTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a number-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%number_field name:"name" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%number_field name%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class NumberFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'number'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('number_field', NumberFieldTag)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a text-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%assign airports = "Eindhoven, Schiphol" | split: ', '%}
|
|
7
|
+
# {%options_for_select airports%}
|
|
8
|
+
#
|
|
9
|
+
# == Advanced usage:
|
|
10
|
+
# {%assign airports = "Eindhoven, Schiphol" | split: ', '%}
|
|
11
|
+
# {%options_for_select airports selected:"Schiphol" disabled:"Eindhoven"%}
|
|
12
|
+
#
|
|
13
|
+
# == Advanced usage:
|
|
14
|
+
# {%options_for_select airports name value selected:"Schiphol" disabled:"Eindhoven"%}
|
|
15
|
+
#
|
|
16
|
+
# This last usage requires a model on the form
|
|
17
|
+
#
|
|
18
|
+
class OptionsForSelectTag < LiquidumTag
|
|
19
|
+
def render(context)
|
|
20
|
+
super
|
|
21
|
+
|
|
22
|
+
options = argv1.map(&:to_liquid)
|
|
23
|
+
|
|
24
|
+
if sargs.present?
|
|
25
|
+
options = options.map do |option|
|
|
26
|
+
result = sargs.map { |a| option[a.to_s] }
|
|
27
|
+
result = result.first if result.length == 1
|
|
28
|
+
result
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context.registers['controller'].helpers.options_for_select(options, attr_args).to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
Liquid::Template.register_tag('options_for_select', OptionsForSelectTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a password-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%password_field name:"name" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%password_field name%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class PasswordFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'password'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('password_field', PasswordFieldTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a search-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%search_field name:"name" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%search_field name%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class SearchFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'search'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('search_field', SearchFieldTag)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Full-text searches content, in both content and properties
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%search q%}
|
|
7
|
+
# {{search|size}} results
|
|
8
|
+
# {%endsearch%}
|
|
9
|
+
#
|
|
10
|
+
# Note: It will only look at published content
|
|
11
|
+
class SearchTag < LiquidumBlock
|
|
12
|
+
def render(context)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
current_content = context.registers['content']
|
|
16
|
+
request = context.registers['controller'].request
|
|
17
|
+
|
|
18
|
+
contents = current_content.site.contents.published.search(request.params[argv1])
|
|
19
|
+
|
|
20
|
+
result = ''
|
|
21
|
+
context.stack do
|
|
22
|
+
context['results'] = contents.map { |content| Scribo::ContentDrop.new(content) }
|
|
23
|
+
result += render_body
|
|
24
|
+
end
|
|
25
|
+
result
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Liquid::Template.register_tag('search', SearchTag)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Adds a (by default submit) button
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%select name:'group'%}{%endselect%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%select group%}{%endselect%}
|
|
10
|
+
#
|
|
11
|
+
class SelectTag < LiquidumBlock
|
|
12
|
+
def render(context)
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
%[<select] + attr_str(:name, arg(:name), input(:name, argv1)) +
|
|
16
|
+
attr_str(:id, arg(:id), input(:id, argv1)) +
|
|
17
|
+
attrs_str(reject: %[name id]) +
|
|
18
|
+
%[>] + render_body + %[</select>]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Liquid::Template.register_tag('select', SelectTag)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Adds SEO tags
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%seo%}
|
|
7
|
+
#
|
|
8
|
+
class SeoTag < LiquidumTag
|
|
9
|
+
def render(context)
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
content = context.registers['content']
|
|
13
|
+
site = content.site
|
|
14
|
+
request = context.registers['controller'].request
|
|
15
|
+
|
|
16
|
+
%[
|
|
17
|
+
<!-- Begin Scribo SEO tag #{Scribo::VERSION} -->
|
|
18
|
+
<title>#{site.properties['title']}</title>
|
|
19
|
+
<meta name="generator" content="Scribo #{Scribo::VERSION}" />
|
|
20
|
+
<meta property="og:title" content="#{content.site.title}" />
|
|
21
|
+
<meta name="author" content="#{site.properties['author'].is_a?(String) ? site.properties['author'] : ''}" />
|
|
22
|
+
<meta property="og:locale" content="en_US" />
|
|
23
|
+
<meta name="description" content="#{site.properties['description']}" />
|
|
24
|
+
<meta property="og:description" content="#{site.properties['description']}" />
|
|
25
|
+
<link rel="canonical" href="#{request.protocol + request.host}" />
|
|
26
|
+
<meta property="og:url" content="#{request.protocol + request.host}" />
|
|
27
|
+
<meta property="og:site_name" content="#{content.site.title}" />
|
|
28
|
+
<script type="application/ld+json">
|
|
29
|
+
{"url":"#{request.protocol + request.host}","headline":"#{site.properties['title']}","name":"#{site.properties['title']}","author":{"@type":"Person","name":"#{site.properties['author']}"},"description":"#{site.properties['description']}","@type":"WebSite","@context":"https://schema.org"}</script>
|
|
30
|
+
<!-- End Scribo SEO tag -->
|
|
31
|
+
]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Liquid::Template.register_tag('seo', SeoTag)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Sets the value in the session
|
|
4
|
+
#
|
|
5
|
+
# {%set_session name value%}
|
|
6
|
+
# {%set_session locale 'nl'%}
|
|
7
|
+
# {%set_session locale request.query_parameters['lang']%}
|
|
8
|
+
# {%set_session locale request.query_parameters['lang']%}
|
|
9
|
+
# {%set_session coupon_code 'beyou'%}
|
|
10
|
+
class SetSessionTag < LiquidumTag
|
|
11
|
+
def render(context)
|
|
12
|
+
super
|
|
13
|
+
|
|
14
|
+
context.registers['controller'].session[argv1] = sargs.first
|
|
15
|
+
''
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Liquid::Template.register_tag('set_session', SetSessionTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a telephone-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%telephone_field name:"phone" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%telephone_field phone%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class TelephoneFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'tel'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('telephone_field', TelephoneFieldTag)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a text-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%text_field name:"name" value:"Pencil"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%text_field name%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
class TextFieldTag < LiquidumTag
|
|
14
|
+
attr_accessor :field_type
|
|
15
|
+
|
|
16
|
+
def initialize(tag, args, tokens)
|
|
17
|
+
super
|
|
18
|
+
@field_type = 'text'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def render(context)
|
|
22
|
+
super
|
|
23
|
+
|
|
24
|
+
result = %[<input] +
|
|
25
|
+
attr_str(:name, arg(:name), input(:name, argv1)) +
|
|
26
|
+
attr_str(:id, arg(:id), input(:id, argv1)) +
|
|
27
|
+
attr_str(:value, arg(:value), input(:value, argv1))
|
|
28
|
+
|
|
29
|
+
result += attrs_str(reject: %[name value id])
|
|
30
|
+
result += %[ type="#{field_type}"/>]
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Liquid::Template.register_tag('text_field', TextFieldTag)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a text-area, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%textarea name:"name"%}{%endtextarea%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%textarea name%}{%endtextarea%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
class TextareaTag < LiquidumBlock
|
|
14
|
+
def render(context)
|
|
15
|
+
super
|
|
16
|
+
|
|
17
|
+
result = %[<textarea] +
|
|
18
|
+
attr_str(:name, arg(:name), input(:name, argv1)) +
|
|
19
|
+
attr_str(:id, arg(:id), input(:id, argv1))
|
|
20
|
+
|
|
21
|
+
result += attrs_str(reject: %[name id])
|
|
22
|
+
result += %[>] + render_body + %[</textarea>]
|
|
23
|
+
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Liquid::Template.register_tag('textarea', TextareaTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a time-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%time_field name:"name" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%time_field name%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class TimeFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'time'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('time_field', TimeFieldTag)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add a url-field, either specifying everything manually or using a model object on the form
|
|
4
|
+
#
|
|
5
|
+
# == Basic usage:
|
|
6
|
+
# {%url_field name:"homepage" value:"1"%}
|
|
7
|
+
#
|
|
8
|
+
# == Advanced usage:
|
|
9
|
+
# {%url_field homepage%}
|
|
10
|
+
#
|
|
11
|
+
# This last usage requires a model on the form
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require_relative './text_field_tag'
|
|
15
|
+
|
|
16
|
+
class UrlFieldTag < TextFieldTag
|
|
17
|
+
def initialize(tag, args, tokens)
|
|
18
|
+
super
|
|
19
|
+
@field_type = 'url'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
Liquid::Template.register_tag('url_field', UrlFieldTag)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scribo
|
|
4
|
+
class Preamble
|
|
5
|
+
DEFAULTS = {
|
|
6
|
+
external_encoding: Encoding.default_external
|
|
7
|
+
}.freeze
|
|
8
|
+
|
|
9
|
+
attr_accessor :metadata, :content
|
|
10
|
+
|
|
11
|
+
def initialize(metadata, content)
|
|
12
|
+
@metadata = metadata
|
|
13
|
+
@content = content
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def metadata_with_content
|
|
17
|
+
@metadata.to_yaml + "---\n" + @content
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def dump
|
|
21
|
+
metadata_with_content
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def save(path, options = {})
|
|
25
|
+
options = DEFAULTS.merge(options)
|
|
26
|
+
|
|
27
|
+
File.open(path, "w:#{options[:external_encoding]}") do |f|
|
|
28
|
+
f.write metadata_with_content
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.parse(data)
|
|
33
|
+
preamble_lines = +''
|
|
34
|
+
content_lines = +''
|
|
35
|
+
|
|
36
|
+
state = :before_preamble
|
|
37
|
+
|
|
38
|
+
f = StringIO.new(data)
|
|
39
|
+
f.each do |line|
|
|
40
|
+
stripped = line.strip
|
|
41
|
+
|
|
42
|
+
case state
|
|
43
|
+
when :before_preamble
|
|
44
|
+
|
|
45
|
+
new_state = case stripped
|
|
46
|
+
when '---'
|
|
47
|
+
:preamble
|
|
48
|
+
when ''
|
|
49
|
+
:before_preamble
|
|
50
|
+
else
|
|
51
|
+
content_lines << line
|
|
52
|
+
:after_preamble
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
when :preamble
|
|
56
|
+
|
|
57
|
+
new_state = case stripped
|
|
58
|
+
when '---'
|
|
59
|
+
:after_preamble
|
|
60
|
+
else
|
|
61
|
+
preamble_lines << line
|
|
62
|
+
:preamble
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
when :after_preamble
|
|
66
|
+
new_state = :after_preamble
|
|
67
|
+
content_lines << line
|
|
68
|
+
|
|
69
|
+
else
|
|
70
|
+
raise "Invalid State: #{state}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
state = new_state
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
new(Scribo::Utility.yaml_safe_parse(preamble_lines), content_lines)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.load(path, options = {})
|
|
80
|
+
f = File.open(path, "r:#{options[:external_encoding]}")
|
|
81
|
+
parse(f.read)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.load_multiple(*paths)
|
|
85
|
+
options = paths.last.is_a?(Hash) ? paths.pop : {}
|
|
86
|
+
paths.map { |path| Preamble.load(path, options) }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scribo
|
|
4
|
+
module SassC
|
|
5
|
+
class Importer < ::SassC::Importer
|
|
6
|
+
def imports(path, parent_path)
|
|
7
|
+
content = options[:content]
|
|
8
|
+
|
|
9
|
+
import_path = ''
|
|
10
|
+
if path.start_with?('/')
|
|
11
|
+
import_path += path
|
|
12
|
+
else
|
|
13
|
+
import_path += content.site.sass_dir
|
|
14
|
+
import_path += '/' unless import_path.end_with?('/')
|
|
15
|
+
|
|
16
|
+
import_path += path
|
|
17
|
+
import_path += File.extname(content.path)
|
|
18
|
+
import_path = File.expand_path(import_path, content.site.sass_dir)
|
|
19
|
+
unless import_path.start_with?(content.site.sass_dir)
|
|
20
|
+
# import_path always starts with /
|
|
21
|
+
import_path = content.site.sass_dir + import_path[1..-1]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
include_content = content.site.contents.where(kind: 'text').located(import_path, restricted: false)
|
|
26
|
+
unless include_content.present?
|
|
27
|
+
# Look for /_file.ext alternative
|
|
28
|
+
import_path = File.dirname(import_path) + '/_' + File.basename(import_path)
|
|
29
|
+
include_content = content.site.contents.where(kind: 'text').located(import_path, restricted: false)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Look in parent's folder
|
|
33
|
+
if include_content.blank? && File.dirname(parent_path) != '.'
|
|
34
|
+
import_path = content.site.sass_dir + File.dirname(parent_path) + '/' + File.basename(import_path)
|
|
35
|
+
include_content = content.site.contents.where(kind: 'text').located(import_path, restricted: false)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if include_content.empty? && content.site.properties.value_at_keypath('sass.sass_dir')
|
|
39
|
+
alternate_path = content.site.properties.value_at_keypath('sass.sass_dir')
|
|
40
|
+
# alternate_path += '/' unless alternate_path.end_with?('/')
|
|
41
|
+
alternate_path = '/' + alternate_path unless alternate_path.start_with?('/')
|
|
42
|
+
|
|
43
|
+
import_path = File.expand_path(path, alternate_path)
|
|
44
|
+
import_path += File.extname(content.path)
|
|
45
|
+
|
|
46
|
+
include_content = content.site.contents.where(kind: 'text').located(import_path, restricted: false)
|
|
47
|
+
|
|
48
|
+
unless include_content.present?
|
|
49
|
+
# Look for /_file.ext alternative
|
|
50
|
+
import_path = File.dirname(import_path) + '/_' + File.basename(import_path)
|
|
51
|
+
include_content = content.site.contents.located(import_path, restricted: false)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
Scribo.config.logger.warn "SassC::Importer: No import found: #{import_path}" unless include_content.first
|
|
57
|
+
# FIXME: Add context
|
|
58
|
+
# Here we don't use a filter
|
|
59
|
+
source = ContentRenderService.new(include_content.first, {}, filter: nil).call || ''
|
|
60
|
+
::SassC::Importer::Import.new(path, source: source)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
module Tilt
|
|
67
|
+
class Template
|
|
68
|
+
def eval_file
|
|
69
|
+
options[:full_path] || file || '(__TEMPLATE__)'
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|