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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +93 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/config/scribo_manifest.js +2 -0
  6. data/app/assets/javascripts/scribo/scribo.js +1 -0
  7. data/app/assets/stylesheets/scribo/scribo.css +1 -0
  8. data/app/controllers/concerns/maintenance_standards.rb +24 -0
  9. data/app/controllers/scribo/admin/sites/contents_controller.rb +86 -0
  10. data/app/controllers/scribo/admin/sites_controller.rb +61 -0
  11. data/app/controllers/scribo/api/sites_controller.rb +23 -0
  12. data/app/controllers/scribo/application_admin_controller.rb +11 -0
  13. data/app/controllers/scribo/application_controller.rb +6 -0
  14. data/app/controllers/scribo/contents_controller.rb +20 -0
  15. data/app/drops/scribo/action_dispatch/request_drop.rb +15 -0
  16. data/app/drops/scribo/active_model/errors_drop.rb +16 -0
  17. data/app/drops/scribo/application_drop.rb +9 -0
  18. data/app/drops/scribo/array_drop.rb +13 -0
  19. data/app/drops/scribo/content_drop.rb +73 -0
  20. data/app/drops/scribo/data_drop.rb +35 -0
  21. data/app/drops/scribo/form_drop.rb +26 -0
  22. data/app/drops/scribo/include_drop.rb +13 -0
  23. data/app/drops/scribo/paginator_drop.rb +73 -0
  24. data/app/drops/scribo/site_drop.rb +83 -0
  25. data/app/helpers/scribo/application_helper.rb +13 -0
  26. data/app/jobs/scribo/application_job.rb +6 -0
  27. data/app/models/scribo/application_record.rb +11 -0
  28. data/app/models/scribo/content.rb +378 -0
  29. data/app/models/scribo/site.rb +161 -0
  30. data/app/services/scribo/application_service.rb +9 -0
  31. data/app/services/scribo/content_find_service.rb +69 -0
  32. data/app/services/scribo/content_render_service.rb +127 -0
  33. data/app/services/scribo/site_export_service.rb +41 -0
  34. data/app/services/scribo/site_find_service.rb +26 -0
  35. data/app/services/scribo/site_import_service.rb +96 -0
  36. data/app/views/layouts/scribo.html.slim +1 -0
  37. data/app/views/scribo/admin/sites/_create_sites.html.slim +22 -0
  38. data/app/views/scribo/admin/sites/_sites.html.slim +18 -0
  39. data/app/views/scribo/admin/sites/contents/_form.html.slim +17 -0
  40. data/app/views/scribo/admin/sites/contents/create.json.jbuilder +11 -0
  41. data/app/views/scribo/admin/sites/contents/edit.html.slim +2 -0
  42. data/app/views/scribo/admin/sites/contents/edit.json.jbuilder +9 -0
  43. data/app/views/scribo/admin/sites/contents/index.html.slim +1 -0
  44. data/app/views/scribo/admin/sites/contents/move.json.jbuilder +9 -0
  45. data/app/views/scribo/admin/sites/contents/rename.json.jbuilder +9 -0
  46. data/app/views/scribo/admin/sites/contents/upload.json.jbuilder +9 -0
  47. data/app/views/scribo/admin/sites/import.json.jbuilder +4 -0
  48. data/app/views/scribo/admin/sites/index.html.slim +7 -0
  49. data/app/views/scribo/shared/_entry.html.slim +17 -0
  50. data/app/views/scribo/shared/_ide.html.slim +14 -0
  51. data/app/views/scribo/shared/_tree-view.html.slim +32 -0
  52. data/config/locales/en.yml +39 -0
  53. data/config/routes.rb +35 -0
  54. data/db/migrate/20200123095630_initial_scribo.rb +34 -0
  55. data/db/migrate/20220919124119_add_ancestry_to_scribo_contents.rb +13 -0
  56. data/db/migrate/20220919124749_remove_parent_id_from_scribo_contents.rb +8 -0
  57. data/lib/scribo/action_controller_helpers.rb +51 -0
  58. data/lib/scribo/action_controller_renderers.rb +71 -0
  59. data/lib/scribo/action_view_helpers.rb +17 -0
  60. data/lib/scribo/active_record_helpers.rb +11 -0
  61. data/lib/scribo/configuration.rb +97 -0
  62. data/lib/scribo/engine.rb +24 -0
  63. data/lib/scribo/i18n_store.rb +100 -0
  64. data/lib/scribo/liquid/filters/jekyll_filters.rb +94 -0
  65. data/lib/scribo/liquid/filters/markdownify.rb +11 -0
  66. data/lib/scribo/liquid/filters/url_filters.rb +76 -0
  67. data/lib/scribo/liquid/parser.rb +32 -0
  68. data/lib/scribo/liquid/tags/application_assets_tag.rb +14 -0
  69. data/lib/scribo/liquid/tags/application_js_tag.rb +16 -0
  70. data/lib/scribo/liquid/tags/asset_tag.rb +56 -0
  71. data/lib/scribo/liquid/tags/button_tag.rb +24 -0
  72. data/lib/scribo/liquid/tags/check_box_tag.rb +31 -0
  73. data/lib/scribo/liquid/tags/csrf_meta_tags_tag.rb +16 -0
  74. data/lib/scribo/liquid/tags/date_field_tag.rb +23 -0
  75. data/lib/scribo/liquid/tags/editable_url_tag.rb +19 -0
  76. data/lib/scribo/liquid/tags/email_field_tag.rb +23 -0
  77. data/lib/scribo/liquid/tags/feed_meta_tag.rb +22 -0
  78. data/lib/scribo/liquid/tags/field_error_tag.rb +26 -0
  79. data/lib/scribo/liquid/tags/fields_for_tag.rb +82 -0
  80. data/lib/scribo/liquid/tags/form_tag.rb +57 -0
  81. data/lib/scribo/liquid/tags/google_analytics_javascript_tag.rb +30 -0
  82. data/lib/scribo/liquid/tags/google_tag_manager_javascript_tag.rb +28 -0
  83. data/lib/scribo/liquid/tags/hidden_field_tag.rb +23 -0
  84. data/lib/scribo/liquid/tags/highlight_tag.rb +106 -0
  85. data/lib/scribo/liquid/tags/include_tag.rb +28 -0
  86. data/lib/scribo/liquid/tags/label_tag.rb +24 -0
  87. data/lib/scribo/liquid/tags/number_field_tag.rb +23 -0
  88. data/lib/scribo/liquid/tags/options_for_select.rb +36 -0
  89. data/lib/scribo/liquid/tags/password_field_tag.rb +23 -0
  90. data/lib/scribo/liquid/tags/search_field_tag.rb +23 -0
  91. data/lib/scribo/liquid/tags/search_tag.rb +29 -0
  92. data/lib/scribo/liquid/tags/select_tag.rb +22 -0
  93. data/lib/scribo/liquid/tags/seo_tag.rb +35 -0
  94. data/lib/scribo/liquid/tags/set_session.rb +19 -0
  95. data/lib/scribo/liquid/tags/telephone_field_tag.rb +23 -0
  96. data/lib/scribo/liquid/tags/text_field_tag.rb +35 -0
  97. data/lib/scribo/liquid/tags/textarea_tag.rb +28 -0
  98. data/lib/scribo/liquid/tags/time_field_tag.rb +23 -0
  99. data/lib/scribo/liquid/tags/url_field_tag.rb +23 -0
  100. data/lib/scribo/preamble.rb +89 -0
  101. data/lib/scribo/sassc/importer.rb +72 -0
  102. data/lib/scribo/utility.rb +94 -0
  103. data/lib/scribo/version.rb +5 -0
  104. data/lib/scribo.rb +59 -0
  105. data/lib/tasks/scribo_tasks.rake +28 -0
  106. 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