lei 0.2.10 → 0.3.0
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 +4 -4
- data/bin/_app/_controllers.rb +52 -20
- data/bin/_app/_helpers.rb +57 -0
- data/bin/_app/_root.rb +22 -2
- data/bin/_app/_src.rb +160 -2
- data/bin/_app/_views.rb +33 -0
- data/bin/_new/_content.rb +11 -0
- data/bin/_new/_custom.rb +11 -0
- data/example/controllers/content.rb +0 -19
- data/example/controllers/search.rb +47 -0
- data/example/helpers/content_helpers.rb +43 -0
- data/example/helpers/global_utils.rb +14 -0
- data/example/spec/test/content_helper_spec.rb +2 -60
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ca29e88e1ce1f90aac74c350f1e4dd5a49cc9676b9077463d258f0a802d5ce5
|
4
|
+
data.tar.gz: ff8a288f2be349a7d12c188ce71ff14a4a3c1c085e646e6ee1e4c5872bc76b73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44a37586627c7cbed8bfdde1d13400faa9598b787f349056d8d7a38b0ba0091a6f75bd418faef8041130fc7d5716a36b7dc3e5b1d729e39cf264a4cf8b1d8657
|
7
|
+
data.tar.gz: 4aa80da80edbd18eab88c346935a8b0fbcefb96d4304c2b5f79b221c56447aab320d074cdf0d14056e2ea42a4e93e2dd50b08c211c0f7c058f84caf514becdec
|
data/bin/_app/_controllers.rb
CHANGED
@@ -44,25 +44,6 @@ content = <<~CONTENT
|
|
44
44
|
}
|
45
45
|
end
|
46
46
|
|
47
|
-
get "/filter" do
|
48
|
-
content = ContentHelpers.get_content(settings.content_dir)
|
49
|
-
|
50
|
-
ContentHelpers.filter_content(content, params)
|
51
|
-
redirect 404 if content.length == 0
|
52
|
-
|
53
|
-
url = request.url
|
54
|
-
|
55
|
-
ContentHelpers.time_sort(content)
|
56
|
-
contentParts = ContentHelpers.paginate(content, params, url)
|
57
|
-
|
58
|
-
slim :search_results, locals: {
|
59
|
-
**contentParts,
|
60
|
-
style: ContentHelpers.load_css(settings.stylesheet),
|
61
|
-
title: "Filtered Results",
|
62
|
-
url: url
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
47
|
not_found do
|
67
48
|
slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
|
68
49
|
end
|
@@ -106,9 +87,60 @@ custom = <<~CUSTOM
|
|
106
87
|
end
|
107
88
|
CUSTOM
|
108
89
|
|
90
|
+
search = <<~SEARCH
|
91
|
+
puts "\\tController: Search"
|
92
|
+
|
93
|
+
class SearchController < Sinatra::Base
|
94
|
+
|
95
|
+
set :content_dir, "\#{$root}/{\#{ContentHelpers.get_content_dirs.join(",")}}"
|
96
|
+
set :stylesheet, "search"
|
97
|
+
set :public_folder, $assets_root
|
98
|
+
set :views, $views
|
99
|
+
|
100
|
+
get "/" do
|
101
|
+
url = request.url
|
102
|
+
|
103
|
+
slim :search, locals: {
|
104
|
+
style: ContentHelpers.load_css(settings.stylesheet),
|
105
|
+
title: "Search",
|
106
|
+
url: url
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
post "/query" do
|
111
|
+
redirect ContentHelpers.get_searchdest(params)
|
112
|
+
end
|
113
|
+
|
114
|
+
get "/results" do
|
115
|
+
content = ContentHelpers.get_content(settings.content_dir)
|
116
|
+
|
117
|
+
ContentHelpers.filter_content(content, params)
|
118
|
+
redirect 404 if content.length == 0
|
119
|
+
|
120
|
+
url = request.url
|
121
|
+
|
122
|
+
ContentHelpers.time_sort(content)
|
123
|
+
contentParts = ContentHelpers.paginate(content, params, url)
|
124
|
+
|
125
|
+
slim :search_results, locals: {
|
126
|
+
**contentParts,
|
127
|
+
style: ContentHelpers.load_css("\#{settings.stylesheet}_results"),
|
128
|
+
title: "Filtered Results",
|
129
|
+
url: url
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
not_found do
|
134
|
+
slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
SEARCH
|
139
|
+
|
109
140
|
files = {
|
110
141
|
"content.rb": content,
|
111
|
-
"custom.rb": custom
|
142
|
+
"custom.rb": custom,
|
143
|
+
"search.rb": search
|
112
144
|
}
|
113
145
|
|
114
146
|
loc = "$(pwd)/controllers"
|
data/bin/_app/_helpers.rb
CHANGED
@@ -46,6 +46,10 @@ content = <<~CONTENT
|
|
46
46
|
all - classified
|
47
47
|
end
|
48
48
|
|
49
|
+
def self.get_content_dirs
|
50
|
+
YAML.load_file($contentDirs)
|
51
|
+
end
|
52
|
+
|
49
53
|
def self.get_post(contentDir, title)
|
50
54
|
content = self.get_content(contentDir)
|
51
55
|
|
@@ -54,6 +58,35 @@ content = <<~CONTENT
|
|
54
58
|
content.include?(post) ? [ post ] : []
|
55
59
|
end
|
56
60
|
|
61
|
+
def self.get_searchdest(params)
|
62
|
+
parts = {}
|
63
|
+
|
64
|
+
term = params["term"]
|
65
|
+
|
66
|
+
parts["term"] = self.sanitize_term(term) if !term.nil? && term != ""
|
67
|
+
|
68
|
+
whenp = params["when"]
|
69
|
+
specificity = params["specificity"]
|
70
|
+
|
71
|
+
if !whenp.nil? && whenp != "" && !specificity.nil? && specificity != ""
|
72
|
+
begin
|
73
|
+
whenRange = Date.parse(whenp)
|
74
|
+
year = "year=\#{whenRange.strftime("%Y")}"
|
75
|
+
month = "month=\#{whenRange.strftime("%m")}"
|
76
|
+
day = "day=\#{whenRange.strftime("%d")}"
|
77
|
+
|
78
|
+
parts["year"] = year if specificity.match?(/^(year|month|day)$/)
|
79
|
+
parts["month"] = month if specificity.match?(/^(month|day)$/)
|
80
|
+
parts["day"] = day if specificity == "day"
|
81
|
+
rescue => exception
|
82
|
+
\# TODO: Implement exception handling.
|
83
|
+
\# This block just serves to swallow the exception.
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
return self.mp_eu("search/results", parts, {})
|
88
|
+
end
|
89
|
+
|
57
90
|
<<~load_css
|
58
91
|
This function reads and returns the contents of a CSS file as a string.
|
59
92
|
Its return value gets stored in a variable for ease of interpolation in
|
@@ -64,6 +97,7 @@ content = <<~CONTENT
|
|
64
97
|
`cat \#{$style_root}/\#{filename}.css`
|
65
98
|
end
|
66
99
|
|
100
|
+
\# Merge Params, Encode URL.
|
67
101
|
def self.mp_eu(path, params, replacement)
|
68
102
|
newParams = {}
|
69
103
|
params.each { |k, v| newParams[k] = v }
|
@@ -125,6 +159,15 @@ content = <<~CONTENT
|
|
125
159
|
CARPET.render(content)
|
126
160
|
end
|
127
161
|
end
|
162
|
+
|
163
|
+
def self.sanitize_term(path)
|
164
|
+
bannedChars = YAML.load_file($bannedChars)
|
165
|
+
|
166
|
+
processed = path
|
167
|
+
bannedChars.each { |char| processed = path.gsub(char, "") }
|
168
|
+
|
169
|
+
return processed
|
170
|
+
end
|
128
171
|
|
129
172
|
def self.time_sort(content)
|
130
173
|
content.sort_by! { |c| File::Stat.new(c).mtime }
|
@@ -153,6 +196,8 @@ module GlobalUtils
|
|
153
196
|
$views = "\#{$root}/views"
|
154
197
|
|
155
198
|
$banlist = "\#{$root}/banlist.yml"
|
199
|
+
$contentDirs = "\#{$root}/contentlist.yml"
|
200
|
+
$bannedChars = "\#{$root}/illegalchars.yml"
|
156
201
|
|
157
202
|
<<~AMP
|
158
203
|
AMP Static Header Parts, as of 15 APR 2018:
|
@@ -178,6 +223,18 @@ module GlobalUtils
|
|
178
223
|
$amp_bind = "<script async custom-element=\\"amp-bind\\" src=\\"https://cdn.ampproject.org/v0/amp-bind-0.1.js\\"></script>"
|
179
224
|
end
|
180
225
|
|
226
|
+
def self.assemble_query(params)
|
227
|
+
return "" if params.nil? || params.length == 0
|
228
|
+
|
229
|
+
queryString = ""
|
230
|
+
params.each_index do |idx|
|
231
|
+
sym = idx == 0 ? "?" : "&"
|
232
|
+
queryString += "\#{sym}\#{params[idx]}"
|
233
|
+
end
|
234
|
+
|
235
|
+
return queryString
|
236
|
+
end
|
237
|
+
|
181
238
|
end
|
182
239
|
GLOBAL
|
183
240
|
|
data/bin/_app/_root.rb
CHANGED
@@ -51,6 +51,13 @@ config = <<~CONFIG
|
|
51
51
|
end
|
52
52
|
CONFIG
|
53
53
|
|
54
|
+
contentlist = <<~CONTENTLIST
|
55
|
+
---
|
56
|
+
- content
|
57
|
+
- welcome
|
58
|
+
...
|
59
|
+
CONTENTLIST
|
60
|
+
|
54
61
|
controllerlist = <<~CONTROLLERLIST
|
55
62
|
---
|
56
63
|
-
|
@@ -61,6 +68,10 @@ controllerlist = <<~CONTROLLERLIST
|
|
61
68
|
file: content
|
62
69
|
name: ContentController
|
63
70
|
path: /content
|
71
|
+
-
|
72
|
+
file: search
|
73
|
+
name: SearchController
|
74
|
+
path: /search
|
64
75
|
...
|
65
76
|
CONTROLLERLIST
|
66
77
|
|
@@ -160,10 +171,17 @@ ignore = <<~IGNORE
|
|
160
171
|
# *.md
|
161
172
|
IGNORE
|
162
173
|
|
174
|
+
illegalchars = <<~ILLEGALCHARS
|
175
|
+
---
|
176
|
+
- "."
|
177
|
+
- "/"
|
178
|
+
...
|
179
|
+
ILLEGALCHARS
|
180
|
+
|
163
181
|
launch = <<~LAUNCH
|
164
|
-
|
182
|
+
\#!/bin/bash
|
165
183
|
|
166
|
-
|
184
|
+
\# Provide port number as argument.
|
167
185
|
puma -b tcp://0.0.0.0:$1
|
168
186
|
LAUNCH
|
169
187
|
|
@@ -204,11 +222,13 @@ files = {
|
|
204
222
|
".gitignore": ignore,
|
205
223
|
"banlist.yml": banlist,
|
206
224
|
"config.ru": config,
|
225
|
+
"contentlist.yml": contentlist,
|
207
226
|
"controllerlist.yml": controllerlist,
|
208
227
|
"customlist.yml": customlist,
|
209
228
|
"Dockerfile": dockerfile,
|
210
229
|
"Gemfile": gems,
|
211
230
|
"gulpfile.js": gulp,
|
231
|
+
"illegalchars.yml": illegalchars,
|
212
232
|
"launch.sh": launch,
|
213
233
|
"package.json": package
|
214
234
|
}
|
data/bin/_app/_src.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require_relative "../functions"
|
2
2
|
|
3
3
|
common = <<~COMMON
|
4
|
+
@anim-bg-color: {
|
5
|
+
transition: background-color 0.35s, color 0.35s;
|
6
|
+
};
|
7
|
+
|
4
8
|
@center-vert: {
|
5
9
|
display: flex;
|
6
10
|
flex-direction: column;
|
@@ -24,11 +28,47 @@ common = <<~COMMON
|
|
24
28
|
font-weight: 300;
|
25
29
|
};
|
26
30
|
|
31
|
+
@full-bar-dark: {
|
32
|
+
background-color: rgba(0, 0, 0, 0.9);
|
33
|
+
box-sizing: border-box;
|
34
|
+
color: white;
|
35
|
+
width: 100vw;
|
36
|
+
};
|
37
|
+
|
38
|
+
@full-bar-light: {
|
39
|
+
background-color: rgba(0, 0, 0, 0.1);
|
40
|
+
box-sizing: border-box;
|
41
|
+
width: 100vw;
|
42
|
+
};
|
43
|
+
|
27
44
|
@full-page: {
|
45
|
+
font-size: 14px;
|
28
46
|
width: 100vw;
|
29
47
|
min-height: 100vh;
|
30
48
|
};
|
31
49
|
|
50
|
+
@link-content: {
|
51
|
+
color: black;
|
52
|
+
font-weight: bold;
|
53
|
+
};
|
54
|
+
|
55
|
+
@link-ad: {
|
56
|
+
color: white;
|
57
|
+
text-decoration: none;
|
58
|
+
};
|
59
|
+
|
60
|
+
@link-al: {
|
61
|
+
color: black;
|
62
|
+
text-decoration: none;
|
63
|
+
};
|
64
|
+
|
65
|
+
@spread-vert: {
|
66
|
+
display: flex;
|
67
|
+
flex-direction: column;
|
68
|
+
justify-content: space-between;
|
69
|
+
align-items: center;
|
70
|
+
};
|
71
|
+
|
32
72
|
@std-content: {
|
33
73
|
max-width: 50em;
|
34
74
|
width: 80vw;
|
@@ -44,7 +84,7 @@ common = <<~COMMON
|
|
44
84
|
|
45
85
|
.base-page {
|
46
86
|
-webkit-tap-highlight-color: transparent;
|
47
|
-
font-family:
|
87
|
+
font-family: 'Lato', sans-serif;
|
48
88
|
background-color: rgb(240, 240, 240);
|
49
89
|
@std-margin();
|
50
90
|
|
@@ -66,11 +106,61 @@ common = <<~COMMON
|
|
66
106
|
.space-to-left {
|
67
107
|
padding-left: 1em;
|
68
108
|
}
|
69
|
-
|
109
|
+
|
70
110
|
.space-to-right {
|
71
111
|
padding-right: 1em;
|
72
112
|
}
|
73
113
|
};
|
114
|
+
|
115
|
+
.main-icon {
|
116
|
+
@fs10();
|
117
|
+
padding: 0em;
|
118
|
+
}
|
119
|
+
|
120
|
+
.std-mp {
|
121
|
+
@std-margin();
|
122
|
+
@std-padding();
|
123
|
+
};
|
124
|
+
|
125
|
+
.page-nav-button {
|
126
|
+
padding: 0em;
|
127
|
+
|
128
|
+
a {
|
129
|
+
.std-mp;
|
130
|
+
@anim-bg-color();
|
131
|
+
@full-bar-light();
|
132
|
+
@link-al();
|
133
|
+
bottom: 0vh;
|
134
|
+
display: block;
|
135
|
+
text-align: center;
|
136
|
+
}
|
137
|
+
|
138
|
+
a:hover {
|
139
|
+
@anim-bg-color();
|
140
|
+
@full-bar-dark();
|
141
|
+
@link-ad();
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
.index-section {
|
146
|
+
@full-page();
|
147
|
+
@spread-vert();
|
148
|
+
|
149
|
+
p:nth-child(2) {
|
150
|
+
.main-icon;
|
151
|
+
}
|
152
|
+
|
153
|
+
p:last-child {
|
154
|
+
.page-nav-button;
|
155
|
+
}
|
156
|
+
}
|
157
|
+
|
158
|
+
.return-previous {
|
159
|
+
p:first-child {
|
160
|
+
.page-nav-button;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
74
164
|
COMMON
|
75
165
|
|
76
166
|
content = <<~CONTENT
|
@@ -124,6 +214,72 @@ notfound = <<~NOTFOUND
|
|
124
214
|
}
|
125
215
|
NOTFOUND
|
126
216
|
|
217
|
+
search = <<~SEARCH
|
218
|
+
@import "_common";
|
219
|
+
|
220
|
+
html, body {
|
221
|
+
.base-page;
|
222
|
+
}
|
223
|
+
|
224
|
+
h1 {
|
225
|
+
@fw300();
|
226
|
+
}
|
227
|
+
|
228
|
+
#search {
|
229
|
+
@center-vert();
|
230
|
+
@full-page();
|
231
|
+
|
232
|
+
input, select {
|
233
|
+
border: 1px solid rgb(100, 100, 100);
|
234
|
+
border-radius: 0.2em;
|
235
|
+
display: block;
|
236
|
+
font-size: 1.6em;
|
237
|
+
margin-bottom: 1em;
|
238
|
+
padding: 0.4em;
|
239
|
+
}
|
240
|
+
|
241
|
+
input[type="submit"], select {
|
242
|
+
width: 100%;
|
243
|
+
}
|
244
|
+
|
245
|
+
input:focus, select:focus {
|
246
|
+
outline: none;
|
247
|
+
box-shadow: 0 0 0 0.05em rgba(0, 123, 255, .5);
|
248
|
+
}
|
249
|
+
|
250
|
+
select {
|
251
|
+
-webkit-appearance: none;
|
252
|
+
-moz-appearance: none;
|
253
|
+
appearance: none;
|
254
|
+
}
|
255
|
+
}
|
256
|
+
SEARCH
|
257
|
+
|
258
|
+
searchresults = <<~SEARCHRESULTS
|
259
|
+
@import "_common";
|
260
|
+
|
261
|
+
html, body {
|
262
|
+
.base-page;
|
263
|
+
}
|
264
|
+
|
265
|
+
h1 {
|
266
|
+
@fw300();
|
267
|
+
}
|
268
|
+
|
269
|
+
#results {
|
270
|
+
@center-vert();
|
271
|
+
@full-page();
|
272
|
+
}
|
273
|
+
|
274
|
+
.content {
|
275
|
+
padding-bottom: 8px;
|
276
|
+
padding-left: 24px;
|
277
|
+
padding-right: 24px;
|
278
|
+
padding-top: 24px;
|
279
|
+
@std-content();
|
280
|
+
}
|
281
|
+
SEARCHRESULTS
|
282
|
+
|
127
283
|
welcome = <<~WELCOME
|
128
284
|
@import "_common";
|
129
285
|
|
@@ -162,6 +318,8 @@ files = {
|
|
162
318
|
"_common.less": common,
|
163
319
|
"content.less": content,
|
164
320
|
"notfound.less": notfound,
|
321
|
+
"search.less": search,
|
322
|
+
"search_results.less": searchresults,
|
165
323
|
"welcome.less": welcome
|
166
324
|
}
|
167
325
|
|
data/bin/_app/_views.rb
CHANGED
@@ -78,6 +78,38 @@ results = <<~RESULTS
|
|
78
78
|
== post
|
79
79
|
RESULTS
|
80
80
|
|
81
|
+
search = <<~SEARCH
|
82
|
+
doctype html
|
83
|
+
html[amp]
|
84
|
+
== slim :"global_partials/head",
|
85
|
+
locals: { title: title, style: style, url: url }
|
86
|
+
body
|
87
|
+
div#search
|
88
|
+
h1.content Search
|
89
|
+
form[action="/search/query" method="POST"]
|
90
|
+
input[
|
91
|
+
class="search-input"
|
92
|
+
name="term"
|
93
|
+
placeholder="Search term"
|
94
|
+
type="text"
|
95
|
+
]
|
96
|
+
input[
|
97
|
+
class="search-input"
|
98
|
+
name="when"
|
99
|
+
type="date"
|
100
|
+
]
|
101
|
+
select[name="specificity"]
|
102
|
+
option[value="" selected=true] (All time)
|
103
|
+
option[value="year"] Year
|
104
|
+
option[value="month"] Month
|
105
|
+
option[value="year"] Day
|
106
|
+
input[
|
107
|
+
class="search-input"
|
108
|
+
name="submit"
|
109
|
+
type="submit"
|
110
|
+
]
|
111
|
+
SEARCH
|
112
|
+
|
81
113
|
welcome = <<~WELCOME
|
82
114
|
doctype html
|
83
115
|
html[amp]
|
@@ -103,6 +135,7 @@ files = {
|
|
103
135
|
"content.slim": content,
|
104
136
|
"notfound.slim": notfound,
|
105
137
|
"post.slim": post,
|
138
|
+
"search.slim": search,
|
106
139
|
"search_results.slim": results,
|
107
140
|
"welcome.slim": welcome
|
108
141
|
}
|
data/bin/_new/_content.rb
CHANGED
@@ -28,6 +28,7 @@ def add_new(name)
|
|
28
28
|
initialContent = "# #{capitalizedName}\nYour content goes here."
|
29
29
|
|
30
30
|
cwd = Dir.pwd
|
31
|
+
|
31
32
|
controllers = YAML.load_file("#{cwd}/controllerlist.yml")
|
32
33
|
controllers.select! { |c| c["file"] != downcasedName }
|
33
34
|
|
@@ -37,7 +38,17 @@ def add_new(name)
|
|
37
38
|
"path" => "/#{downcasedName}"
|
38
39
|
}
|
39
40
|
|
41
|
+
controllers.sort! { |a, b| a["file"] <=> b["file"] }
|
42
|
+
|
43
|
+
content = YAML.load_file("#{cwd}/contentlist.yml")
|
44
|
+
content.select! { |c| c != downcasedName }
|
45
|
+
|
46
|
+
content << downcasedName
|
47
|
+
|
48
|
+
content.sort!
|
49
|
+
|
40
50
|
`echo '#{controllers.to_yaml}' > #{cwd}/controllerlist.yml`
|
51
|
+
`echo '#{content.to_yaml}' > #{cwd}/contentlist.yml`
|
41
52
|
`mkdir #{cwd}/#{downcasedName}`
|
42
53
|
`echo '#{initialContent}' > #{cwd}/#{downcasedName}/#{downcasedName}.md`
|
43
54
|
`echo '#{contentController}' > #{cwd}/controllers/#{downcasedName}.rb`
|
data/bin/_new/_custom.rb
CHANGED
@@ -10,6 +10,7 @@ def add_new(name)
|
|
10
10
|
capitalizedName = name.capitalize
|
11
11
|
|
12
12
|
cwd = Dir.pwd
|
13
|
+
|
13
14
|
custom = YAML.load_file("#{cwd}/customlist.yml")
|
14
15
|
custom.select! { |c| c["file"] != downcasedName }
|
15
16
|
|
@@ -20,6 +21,15 @@ def add_new(name)
|
|
20
21
|
"content" => [ "#{downcasedName}.md" ]
|
21
22
|
}
|
22
23
|
|
24
|
+
custom.sort! { |a, b| a["name"] <=> b["name"] }
|
25
|
+
|
26
|
+
content = YAML.load_file("#{cwd}/contentlist.yml")
|
27
|
+
content.select! { |c| c != downcasedName }
|
28
|
+
|
29
|
+
content << downcasedName
|
30
|
+
|
31
|
+
content.sort!
|
32
|
+
|
23
33
|
customView = <<~VIEW
|
24
34
|
doctype html
|
25
35
|
html[amp]
|
@@ -63,6 +73,7 @@ def add_new(name)
|
|
63
73
|
initialContent = "# #{capitalizedName}\n\nYour content goes here."
|
64
74
|
|
65
75
|
`echo '#{custom.to_yaml}' > #{cwd}/customlist.yml`
|
76
|
+
`echo '#{content.to_yaml}' > #{cwd}/contentlist.yml`
|
66
77
|
`mkdir #{cwd}/#{downcasedName}`
|
67
78
|
`echo '#{initialContent}' > #{cwd}/#{downcasedName}/#{downcasedName}.md`
|
68
79
|
`echo '#{customView}' > #{cwd}/views/#{downcasedName}.slim`
|
@@ -41,25 +41,6 @@ class ContentController < Sinatra::Base
|
|
41
41
|
}
|
42
42
|
end
|
43
43
|
|
44
|
-
get "/filter" do
|
45
|
-
content = ContentHelpers.get_content(settings.content_dir)
|
46
|
-
|
47
|
-
ContentHelpers.filter_content(content, params)
|
48
|
-
redirect 404 if content.length == 0
|
49
|
-
|
50
|
-
url = request.url
|
51
|
-
|
52
|
-
ContentHelpers.time_sort(content)
|
53
|
-
contentParts = ContentHelpers.paginate(content, params, url)
|
54
|
-
|
55
|
-
slim :search_results, locals: {
|
56
|
-
**contentParts,
|
57
|
-
style: ContentHelpers.load_css(settings.stylesheet),
|
58
|
-
title: "Filtered Results",
|
59
|
-
url: url
|
60
|
-
}
|
61
|
-
end
|
62
|
-
|
63
44
|
not_found do
|
64
45
|
slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
|
65
46
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
puts "\tController: Search"
|
2
|
+
|
3
|
+
class SearchController < Sinatra::Base
|
4
|
+
|
5
|
+
set :content_dir, "#{$root}/{#{ContentHelpers.get_content_dirs.join(",")}}"
|
6
|
+
set :stylesheet, "search"
|
7
|
+
set :public_folder, $assets_root
|
8
|
+
set :views, $views
|
9
|
+
|
10
|
+
get "/" do
|
11
|
+
url = request.url
|
12
|
+
|
13
|
+
slim :search, locals: {
|
14
|
+
style: ContentHelpers.load_css(settings.stylesheet),
|
15
|
+
title: "Search",
|
16
|
+
url: url
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
post "/query" do
|
21
|
+
redirect ContentHelpers.get_searchdest(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
get "/results" do
|
25
|
+
content = ContentHelpers.get_content(settings.content_dir)
|
26
|
+
|
27
|
+
ContentHelpers.filter_content(content, params)
|
28
|
+
redirect 404 if content.length == 0
|
29
|
+
|
30
|
+
url = request.url
|
31
|
+
|
32
|
+
ContentHelpers.time_sort(content)
|
33
|
+
contentParts = ContentHelpers.paginate(content, params, url)
|
34
|
+
|
35
|
+
slim :search_results, locals: {
|
36
|
+
**contentParts,
|
37
|
+
style: ContentHelpers.load_css("#{settings.stylesheet}_results"),
|
38
|
+
title: "Filtered Results",
|
39
|
+
url: url
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
not_found do
|
44
|
+
slim :notfound, locals: { **ContentHelpers.nf_404, url: request.url }
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -43,6 +43,10 @@ module ContentHelpers
|
|
43
43
|
all - classified
|
44
44
|
end
|
45
45
|
|
46
|
+
def self.get_content_dirs
|
47
|
+
YAML.load_file($contentDirs)
|
48
|
+
end
|
49
|
+
|
46
50
|
def self.get_post(contentDir, title)
|
47
51
|
content = self.get_content(contentDir)
|
48
52
|
|
@@ -51,6 +55,35 @@ module ContentHelpers
|
|
51
55
|
content.include?(post) ? [ post ] : []
|
52
56
|
end
|
53
57
|
|
58
|
+
def self.get_searchdest(params)
|
59
|
+
parts = {}
|
60
|
+
|
61
|
+
term = params["term"]
|
62
|
+
|
63
|
+
parts["term"] = self.sanitize_term(term) if !term.nil? && term != ""
|
64
|
+
|
65
|
+
whenp = params["when"]
|
66
|
+
specificity = params["specificity"]
|
67
|
+
|
68
|
+
if !whenp.nil? && whenp != "" && !specificity.nil? && specificity != ""
|
69
|
+
begin
|
70
|
+
whenRange = Date.parse(whenp)
|
71
|
+
year = "year=#{whenRange.strftime("%Y")}"
|
72
|
+
month = "month=#{whenRange.strftime("%m")}"
|
73
|
+
day = "day=#{whenRange.strftime("%d")}"
|
74
|
+
|
75
|
+
parts["year"] = year if specificity.match?(/^(year|month|day)$/)
|
76
|
+
parts["month"] = month if specificity.match?(/^(month|day)$/)
|
77
|
+
parts["day"] = day if specificity == "day"
|
78
|
+
rescue => exception
|
79
|
+
# TODO: Implement exception handling.
|
80
|
+
# This block just serves to swallow the exception.
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
return self.mp_eu("search/results", parts, {})
|
85
|
+
end
|
86
|
+
|
54
87
|
<<~load_css
|
55
88
|
This function reads and returns the contents of a CSS file as a string.
|
56
89
|
Its return value gets stored in a variable for ease of interpolation in
|
@@ -61,6 +94,7 @@ module ContentHelpers
|
|
61
94
|
`cat #{$style_root}/#{filename}.css`
|
62
95
|
end
|
63
96
|
|
97
|
+
# Merge Params, Encode URL.
|
64
98
|
def self.mp_eu(path, params, replacement)
|
65
99
|
newParams = {}
|
66
100
|
params.each { |k, v| newParams[k] = v }
|
@@ -123,6 +157,15 @@ module ContentHelpers
|
|
123
157
|
end
|
124
158
|
end
|
125
159
|
|
160
|
+
def self.sanitize_term(path)
|
161
|
+
bannedChars = YAML.load_file($bannedChars)
|
162
|
+
|
163
|
+
processed = path
|
164
|
+
bannedChars.each { |char| processed = path.gsub(char, "") }
|
165
|
+
|
166
|
+
return processed
|
167
|
+
end
|
168
|
+
|
126
169
|
def self.time_sort(content)
|
127
170
|
content.sort_by! { |c| File::Stat.new(c).mtime }
|
128
171
|
content.reverse!
|
@@ -16,6 +16,8 @@ module GlobalUtils
|
|
16
16
|
$views = "#{$root}/views"
|
17
17
|
|
18
18
|
$banlist = "#{$root}/banlist.yml"
|
19
|
+
$contentDirs = "#{$root}/contentlist.yml"
|
20
|
+
$bannedChars = "#{$root}/illegalchars.yml"
|
19
21
|
|
20
22
|
<<~AMP
|
21
23
|
AMP Static Header Parts, as of 15 APR 2018:
|
@@ -41,4 +43,16 @@ module GlobalUtils
|
|
41
43
|
$amp_bind = "<script async custom-element=\"amp-bind\" src=\"https://cdn.ampproject.org/v0/amp-bind-0.1.js\"></script>"
|
42
44
|
end
|
43
45
|
|
46
|
+
def self.assemble_query(params)
|
47
|
+
return "" if params.nil? || params.length == 0
|
48
|
+
|
49
|
+
queryString = ""
|
50
|
+
params.each_index do |idx|
|
51
|
+
sym = idx == 0 ? "?" : "&"
|
52
|
+
queryString += "#{sym}#{params[idx]}"
|
53
|
+
end
|
54
|
+
|
55
|
+
return queryString
|
56
|
+
end
|
57
|
+
|
44
58
|
end
|
@@ -12,28 +12,16 @@ RSpec.describe "Tests Module: ContentHelpers" do
|
|
12
12
|
content = ContentHelpers.get_content(fixtures)
|
13
13
|
|
14
14
|
it "Tests variable $banlist: Verifies exclusion" do
|
15
|
-
expect(content.length).
|
15
|
+
expect(content.length).to eq 6
|
16
16
|
expect(content).not_to include "#{fixtures}/md-2.md"
|
17
17
|
end
|
18
18
|
|
19
|
-
it "Tests method time_sort: Correctly sorts by mtime" do
|
20
|
-
ContentHelpers.time_sort(content)
|
21
|
-
|
22
|
-
expect(content.first).to eq "#{fixtures}/md-1.md"
|
23
|
-
expect(content.last).to eq "#{fixtures}/md-3.md"
|
24
|
-
end
|
25
|
-
|
26
19
|
just6 = []
|
27
20
|
for i in 1..7
|
28
21
|
just6 << "#{fixtures}/md-#{i}.md" if i != 2
|
29
22
|
end
|
30
23
|
ContentHelpers.time_sort(just6)
|
31
24
|
|
32
|
-
it "Tests method get_content: Correctly retrieves content" do
|
33
|
-
expect(content.length).to eq 6
|
34
|
-
expect(content).to eq just6
|
35
|
-
end
|
36
|
-
|
37
25
|
it "Tests method get_post: Correctly retrieves post" do
|
38
26
|
post = ContentHelpers.get_post(fixtures, "md-4")
|
39
27
|
ContentHelpers.time_sort(post)
|
@@ -115,52 +103,6 @@ RSpec.describe "Tests Module: ContentHelpers" do
|
|
115
103
|
expect(filtered[0]).to eq "#{fixtures}/md-3.md"
|
116
104
|
end
|
117
105
|
|
118
|
-
it "Tests method filter_content: Correctly filters on year" do
|
119
|
-
params = { "year" => "2018" }
|
120
|
-
filtered = just6.clone
|
121
|
-
ContentHelpers.filter_content(filtered, params)
|
122
|
-
|
123
|
-
expect(filtered.length).to eq 6
|
124
|
-
|
125
|
-
params2 = { "year" => "2017" }
|
126
|
-
ContentHelpers.filter_content(filtered, params2)
|
127
|
-
|
128
|
-
expect(filtered.length).to eq 0
|
129
|
-
end
|
130
|
-
|
131
|
-
it "Tests method filter_content: Correctly filters on month" do
|
132
|
-
params = { "year" => "2018", "month" => "05" }
|
133
|
-
filtered = just6.clone
|
134
|
-
ContentHelpers.filter_content(filtered, params)
|
135
|
-
|
136
|
-
expect(filtered.length).to eq 6
|
137
|
-
|
138
|
-
params2 = { "year" => "2018", "month" => "04" }
|
139
|
-
ContentHelpers.filter_content(filtered, params2)
|
140
|
-
|
141
|
-
expect(filtered.length).to eq 0
|
142
|
-
end
|
143
|
-
|
144
|
-
it "Tests method filter_content: Correctly filters on day" do
|
145
|
-
params = { "year" => "2018", "month" => "05", "day" => "03" }
|
146
|
-
filtered = just6.clone
|
147
|
-
ContentHelpers.filter_content(filtered, params)
|
148
|
-
|
149
|
-
expect(filtered.length).to eq 4
|
150
|
-
|
151
|
-
params2 = { "year" => "2018", "month" => "05", "day" => "10" }
|
152
|
-
filtered2 = just6.clone
|
153
|
-
ContentHelpers.filter_content(filtered2, params2)
|
154
|
-
|
155
|
-
expect(filtered2.length).to eq 1
|
156
|
-
|
157
|
-
params3 = { "year" => "2018", "month" => "05", "day" => "04" }
|
158
|
-
filtered3 = just6.clone
|
159
|
-
ContentHelpers.filter_content(filtered3, params3)
|
160
|
-
|
161
|
-
expect(filtered3.length).to eq 1
|
162
|
-
end
|
163
|
-
|
164
106
|
it "Tests method parse_md: Correctly generates HTML from Markdown" do
|
165
107
|
converted = ContentHelpers.parse_md([ "#{fixtures}/md-1.md" ])
|
166
108
|
|
@@ -170,7 +112,7 @@ RSpec.describe "Tests Module: ContentHelpers" do
|
|
170
112
|
it "Tests method load_css: Correctly returns CSS file contents" do
|
171
113
|
processed = ContentHelpers.load_css("test")
|
172
114
|
|
173
|
-
expect(processed).to eq ".mock{display: none;}"
|
115
|
+
expect(processed).to eq ".mock{display: none;}\n"
|
174
116
|
end
|
175
117
|
|
176
118
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lei
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Chang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- bin/lei
|
63
63
|
- example/controllers/content.rb
|
64
64
|
- example/controllers/custom.rb
|
65
|
+
- example/controllers/search.rb
|
65
66
|
- example/controllers/test.rb
|
66
67
|
- example/helpers/content_helpers.rb
|
67
68
|
- example/helpers/global_utils.rb
|