scribo 1.0.38

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