hyde_admin 0.0.13 → 0.0.14
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/.gitignore +3 -1
- data/.rspec +3 -0
- data/CHANGELOG.md +31 -0
- data/CLAUDE.md +56 -0
- data/Gemfile +8 -0
- data/bin/admin_views/admin_layout.html.erb +76 -51
- data/bin/admin_views/configuration.erb +4 -4
- data/bin/admin_views/dashboard.erb +37 -1
- data/bin/admin_views/editor_html.erb +21 -18
- data/bin/admin_views/editor_js.erb +112 -111
- data/bin/admin_views/files/edit.erb +4 -4
- data/bin/admin_views/files/listing.erb +14 -14
- data/bin/admin_views/posts/edit.erb +159 -62
- data/bin/admin_views/posts/listing.erb +10 -10
- data/bin/admin_views/search.erb +42 -0
- data/bin/admin_views/upload_image_form.erb +5 -5
- data/bin/hyde_admin.ru +165 -11
- data/bin/hyde_assets/hyde_admin.css +58 -0
- data/bin/hyde_assets/hyde_admin.js +121 -18
- data/bin/i18n/en.yml +20 -1
- data/bin/i18n/fr.yml +21 -2
- data/hyde_admin.gemspec +6 -8
- data/lib/hyde_admin/version.rb +1 -1
- data/spec/files/create_file_spec.rb +92 -0
- data/spec/mid_helpers_spec.rb +105 -0
- data/spec/posts/create_draft_spec.rb +77 -0
- data/spec/posts/create_page_spec.rb +75 -0
- data/spec/posts/create_post_spec.rb +100 -0
- data/spec/search/global_search_spec.rb +92 -0
- data/spec/spec_helper.rb +25 -0
- metadata +26 -34
- data/.idea/.gitignore +0 -8
- data/.idea/hyde_admin.iml +0 -25
- data/.idea/misc.xml +0 -4
- data/.idea/modules.xml +0 -8
- data/.idea/vcs.xml +0 -6
|
@@ -1,58 +1,67 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div id="preview-wrapper">
|
|
2
|
+
<div id="editor-panel">
|
|
3
|
+
<h2><%= CGI.escapeHTML t.send(@type_file).capitalize %></h2>
|
|
2
4
|
|
|
3
5
|
<% file_params = (!@new_record ? "?file=#{@file}" : "") %>
|
|
4
6
|
|
|
5
|
-
<form action="/<%= @type_file %><%= file_params %>" method="post">
|
|
7
|
+
<form action="/<%= @type_file %><%= file_params %>" method="post" data-autosave-key="hyde_autosave:<%= @new_record ? "new:#{@type_file}" : @file %>">
|
|
8
|
+
<div id="autosave-banner" class="alert alert-warning d-none mb-3" role="alert">
|
|
9
|
+
<i class="fa-solid fa-clock-rotate-left"></i>
|
|
10
|
+
<span id="autosave-banner-text"></span>
|
|
11
|
+
<button type="button" class="btn btn-sm btn-warning ms-2" id="autosave-restore">Restore</button>
|
|
12
|
+
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" id="autosave-discard">Discard</button>
|
|
13
|
+
</div>
|
|
6
14
|
<% if !@new_record %>
|
|
7
15
|
<div class="mb-3">
|
|
8
|
-
<label for="i-path" class="form-label"><%=
|
|
16
|
+
<label for="i-path" class="form-label"><%= CGI.escapeHTML t.path.capitalize %></label>
|
|
9
17
|
<div class="input-group">
|
|
10
18
|
<span class="input-group-text">
|
|
11
|
-
<i class="fas fa-calendar-alt" id="btn-date-path" title="<%=
|
|
19
|
+
<i class="fas fa-calendar-alt" id="btn-date-path" title="<%= CGI.escapeHTML t.change_date_path %>"></i>
|
|
12
20
|
</span>
|
|
13
21
|
<span class="input-group-text">
|
|
14
|
-
<i class="fas fa-sync-alt" id="btn-title-path" title="<%=
|
|
22
|
+
<i class="fas fa-sync-alt" id="btn-title-path" title="<%= CGI.escapeHTML t.change_title_path %>"></i>
|
|
15
23
|
</span>
|
|
16
|
-
<input type="text" class="form-control" value="<%= @file %>" name="new_file" id="i-path">
|
|
24
|
+
<input type="text" class="form-control" value="<%= CGI.escapeHTML(@file) %>" name="new_file" id="i-path">
|
|
17
25
|
</div>
|
|
18
|
-
<div id="i-path-help" class="form-text"><%=
|
|
26
|
+
<div id="i-path-help" class="form-text"><%= CGI.escapeHTML t.help_path %></div>
|
|
19
27
|
</div>
|
|
20
28
|
<% end %>
|
|
21
29
|
|
|
22
30
|
<div class="mb-3">
|
|
23
|
-
<label for="i-title" class="form-label"><%=
|
|
24
|
-
<input type="text" value="<%= @headers.delete('title') %>" class="form-control" name="title" id="i-title">
|
|
31
|
+
<label for="i-title" class="form-label"><%= CGI.escapeHTML t.title.capitalize %></label>
|
|
32
|
+
<input type="text" value="<%= CGI.escapeHTML(@headers.delete('title').to_s) %>" class="form-control" name="title" id="i-title">
|
|
25
33
|
</div>
|
|
26
34
|
<div class="mb-3">
|
|
27
|
-
<label for="i-date" class="form-label"><%=
|
|
35
|
+
<label for="i-date" class="form-label"><%= CGI.escapeHTML t.date.capitalize %></label>
|
|
28
36
|
<div class="input-group">
|
|
29
37
|
<span class="input-group-text">
|
|
30
|
-
<i class="fas fa-calendar-day" id="btn-date-today" title="<%=
|
|
38
|
+
<i class="fas fa-calendar-day" id="btn-date-today" title="<%= CGI.escapeHTML t.set_date_today %>"></i>
|
|
31
39
|
</span>
|
|
32
|
-
<input type="text" value="<%= @headers.delete('date') || Time.now.strftime('%Y-%m-%d %H:%M:%S %z') %>" class="form-control" name="date" id="i-date">
|
|
40
|
+
<input type="text" value="<%= CGI.escapeHTML((@headers.delete('date') || Time.now.strftime('%Y-%m-%d %H:%M:%S %z')).to_s) %>" class="form-control" name="date" id="i-date">
|
|
33
41
|
</div>
|
|
34
42
|
</div>
|
|
35
43
|
<div class="mb-3">
|
|
36
|
-
<label for="i-tags" class="form-label"><%=
|
|
37
|
-
<input type="text" value="<%= Mid.extract_tags(@headers.delete('tags')).join(',') %>" class="form-control" name="tags" id="i-tags">
|
|
38
|
-
<div id="i-tags-help" class="form-text"><%=
|
|
44
|
+
<label for="i-tags" class="form-label"><%= CGI.escapeHTML t.tags.capitalize %></label>
|
|
45
|
+
<input type="text" value="<%= CGI.escapeHTML(Mid.extract_tags(@headers.delete('tags')).join(',')) %>" class="form-control" name="tags" id="i-tags">
|
|
46
|
+
<div id="i-tags-help" class="form-text"><%= CGI.escapeHTML t.help_tags.capitalize %></div>
|
|
39
47
|
</div>
|
|
40
48
|
|
|
41
49
|
<% if @type_file == 'drafts' %>
|
|
42
50
|
<div class="mb-3 form-check">
|
|
43
51
|
<input type="checkbox" class="form-check-input" name="publish" value="publish" id="i-publish">
|
|
44
|
-
<label class="form-check-label" for="i-publish"><%=
|
|
52
|
+
<label class="form-check-label" for="i-publish"><%= CGI.escapeHTML t.publish.capitalize %></label>
|
|
45
53
|
</div>
|
|
46
54
|
<% end %>
|
|
47
55
|
|
|
48
56
|
<% selected_layout = @headers.delete('layout') %>
|
|
49
57
|
<% selected_layout = @hyde_parameters['default_layout'] if selected_layout.nil? || selected_layout.empty? %>
|
|
58
|
+
<% available_layouts = Dir.glob(File.join(Dir.pwd, '_layouts', '*')).map { |f| File.basename(f, File.extname(f)) } %>
|
|
59
|
+
<% available_layouts.unshift(selected_layout) unless selected_layout.nil? || available_layouts.include?(selected_layout) %>
|
|
50
60
|
<% if @hyde_parameters['display_layout'].to_s == 'true' %>
|
|
51
61
|
<div class="mb-3">
|
|
52
|
-
<label for="i-layout" class="form-label"><%=
|
|
62
|
+
<label for="i-layout" class="form-label"><%= CGI.escapeHTML t.layout.capitalize %></label>
|
|
53
63
|
<select class="form-select" aria-label="Choice layout" name="layout">
|
|
54
|
-
<%
|
|
55
|
-
<% layout_loop = File.basename(f, File.extname(f)) %>
|
|
64
|
+
<% available_layouts.each do |layout_loop| %>
|
|
56
65
|
<option <%= (layout_loop == selected_layout ? 'selected' : '') %> value="<%= layout_loop %>"><%= layout_loop %></option>
|
|
57
66
|
<% end %>
|
|
58
67
|
</select>
|
|
@@ -65,7 +74,7 @@
|
|
|
65
74
|
<% selected_format = ".#{@hyde_parameters['default_format']}" if selected_format.empty? %>
|
|
66
75
|
<% if @hyde_parameters['display_format'].to_s == 'true' %>
|
|
67
76
|
<div class="mb-3">
|
|
68
|
-
<label for="i-format" class="form-label"><%=
|
|
77
|
+
<label for="i-format" class="form-label"><%= CGI.escapeHTML t.format.capitalize %></label>
|
|
69
78
|
<select class="form-select" id="select-format" aria-label="Choice format" name="format">
|
|
70
79
|
<% { 'html' => 'html', 'markdown' => 'md' }.each do |k, v| %>
|
|
71
80
|
<option <%= (selected_format == ".#{v}" ? 'selected' : '') %> value="<%= v %>"><%= k %></option>
|
|
@@ -81,78 +90,166 @@
|
|
|
81
90
|
|
|
82
91
|
<% @headers.each do |k,v| %>
|
|
83
92
|
<div class="mb-3">
|
|
84
|
-
<label for="i-<%= k %>" class="form-label"><%= k %></label>
|
|
85
|
-
<input type="text" value="<%= v %>" class="form-control" name="<%= k %>" id="i-<%= k %>">
|
|
93
|
+
<label for="i-<%= CGI.escapeHTML(k) %>" class="form-label"><%= CGI.escapeHTML(k) %></label>
|
|
94
|
+
<input type="text" value="<%= CGI.escapeHTML(v.to_s) %>" class="form-control" name="<%= CGI.escapeHTML(k) %>" id="i-<%= CGI.escapeHTML(k) %>">
|
|
86
95
|
</div>
|
|
87
96
|
<% end %>
|
|
88
97
|
|
|
89
|
-
<a href="#" class="btn btn-secondary mb-2" id="add-header"><i class="fas fa-plus"></i> <%=
|
|
98
|
+
<a href="#" class="btn btn-secondary mb-2" id="add-header"><i class="fas fa-plus"></i> <%= CGI.escapeHTML t.add_header.capitalize %></a>
|
|
90
99
|
<div class="mb-3 custom-headers"></div>
|
|
91
100
|
|
|
92
101
|
<div class="mb-3 template-header" style="display: none">
|
|
93
102
|
<div class="row">
|
|
94
|
-
<div class="col-sm-4"><input type="text" class="col-sm-6 form-control header-name" name="" placeholder="<%=
|
|
95
|
-
<div class="col-sm-8"><input type="text" class="col-sm-6 form-control header-value" name="" placeholder="<%=
|
|
103
|
+
<div class="col-sm-4"><input type="text" class="col-sm-6 form-control header-name" name="" placeholder="<%= CGI.escapeHTML t.header_name.capitalize %>"></div>
|
|
104
|
+
<div class="col-sm-8"><input type="text" class="col-sm-6 form-control header-value" name="" placeholder="<%= CGI.escapeHTML t.header_value.capitalize %>"></div>
|
|
96
105
|
</div>
|
|
97
106
|
</div>
|
|
98
107
|
|
|
99
108
|
<script type="text/javascript" charset="utf-8">
|
|
100
109
|
window.custom_headers_i = 0;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
document.addEventListener('click', function(e){
|
|
111
|
+
if(!e.target.closest('#add-header')) return;
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
var tpl = document.querySelector('.template-header');
|
|
114
|
+
var clone = tpl.cloneNode(true);
|
|
115
|
+
clone.querySelector('.header-name').setAttribute('name', 'header' + window.custom_headers_i + '[]');
|
|
116
|
+
clone.querySelector('.header-value').setAttribute('name', 'header' + window.custom_headers_i + '[]');
|
|
117
|
+
clone.style.display = '';
|
|
118
|
+
clone.classList.remove('template-header');
|
|
119
|
+
document.querySelector('.custom-headers').appendChild(clone);
|
|
108
120
|
window.custom_headers_i += 1;
|
|
109
|
-
return false;
|
|
110
121
|
});
|
|
111
122
|
</script>
|
|
112
123
|
|
|
113
124
|
<div class="mb-3">
|
|
114
|
-
<label for="i-content" class="form-label"><%=
|
|
125
|
+
<label for="i-content" class="form-label"><%= CGI.escapeHTML t.content.capitalize %> <a href="https://jekyllrb.com/docs/liquid/" class="text-secondary" target="_blank"><i class="fas fa-question-circle"></i></a></label>
|
|
115
126
|
|
|
116
127
|
<% path = File.join(Pathname.new(Mid.gem_source_path), 'admin_views', 'editor_html.erb') %>
|
|
117
128
|
<%= ERB.new(File.read(path)).result(binding) %>
|
|
118
129
|
|
|
119
|
-
<textarea class="form-control text-editor" id="i-content" rows="3" name="content"><%= @content %></textarea>
|
|
130
|
+
<textarea class="form-control text-editor" id="i-content" rows="3" name="content"><%= CGI.escapeHTML(@content.to_s) %></textarea>
|
|
120
131
|
</div>
|
|
121
|
-
<button type="submit" class="btn btn-primary"><%=
|
|
132
|
+
<button type="submit" class="btn btn-primary"><%= CGI.escapeHTML t.submit.capitalize %></button>
|
|
133
|
+
<span id="autosave-indicator"><i class="fa-solid fa-check"></i> Saved</span>
|
|
122
134
|
</form>
|
|
123
135
|
|
|
124
136
|
<script type="text/javascript" charset="utf-8">
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
window.
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
$(document).on('click', '#btn-date-path', function(){
|
|
133
|
-
$.post( "/ajax/update_path_date", { date: $('#i-date').val(), path: $('#i-path').val() })
|
|
134
|
-
.done(function( data ) {
|
|
135
|
-
$('#i-path').val(data);
|
|
136
|
-
});
|
|
137
|
-
return false;
|
|
138
|
-
});
|
|
139
|
-
$(document).on('click', '#btn-title-path', function(){
|
|
140
|
-
$.post( "/ajax/update_path_title", { title: $('#i-title').val(), path: $('#i-path').val() })
|
|
141
|
-
.done(function( data ) {
|
|
142
|
-
$('#i-path').val(data);
|
|
143
|
-
});
|
|
144
|
-
return false;
|
|
137
|
+
document.addEventListener('change', function(e){
|
|
138
|
+
if(!e.target.closest('#select-format')) return;
|
|
139
|
+
var ext_mode = { md: "markdown", html: "htmlmixed"};
|
|
140
|
+
var val = document.getElementById('select-format').value;
|
|
141
|
+
window.myCodeMirror.setOption("mode", ext_mode[val]);
|
|
142
|
+
window.mode_markdown = (val == 'md');
|
|
145
143
|
});
|
|
146
144
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
function postForm(url, params) {
|
|
146
|
+
var body = new URLSearchParams(params);
|
|
147
|
+
return fetch(url, { method: 'POST', body: body }).then(function(r){ return r.text(); });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
document.addEventListener('click', function(e){
|
|
151
|
+
if(e.target.closest('#btn-date-path')){
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
postForm("/ajax/update_path_date", {
|
|
154
|
+
date: document.getElementById('i-date').value,
|
|
155
|
+
path: document.getElementById('i-path').value
|
|
156
|
+
}).then(function(data){ document.getElementById('i-path').value = data; });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if(e.target.closest('#btn-title-path')){
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
postForm("/ajax/update_path_title", {
|
|
162
|
+
title: document.getElementById('i-title').value,
|
|
163
|
+
path: document.getElementById('i-path').value
|
|
164
|
+
}).then(function(data){ document.getElementById('i-path').value = data; });
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if(e.target.closest('#btn-date-today')){
|
|
168
|
+
e.preventDefault();
|
|
169
|
+
postForm("/ajax/update_date_today", {})
|
|
170
|
+
.then(function(data){ document.getElementById('i-date').value = data; });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
153
173
|
});
|
|
154
174
|
|
|
155
175
|
<% path = File.join(Pathname.new(Mid.gem_source_path), 'admin_views', 'editor_js.erb') %>
|
|
156
176
|
<%= ERB.new(File.read(path)).result(binding) %>
|
|
157
177
|
|
|
178
|
+
// Preview functionality
|
|
179
|
+
document.addEventListener('click', function(e) {
|
|
180
|
+
if (e.target.closest('#btn-preview')) {
|
|
181
|
+
e.preventDefault();
|
|
182
|
+
var wrapper = document.getElementById('preview-wrapper');
|
|
183
|
+
var panel = document.getElementById('preview-panel');
|
|
184
|
+
|
|
185
|
+
document.getElementById('waiting').style.display = 'block';
|
|
186
|
+
|
|
187
|
+
var content = window.myCodeMirror ? window.myCodeMirror.getValue() : document.getElementById('i-content').value;
|
|
188
|
+
var layoutEl = document.querySelector('select[name="layout"]') || document.querySelector('input[name="layout"]');
|
|
189
|
+
var formatEl = document.getElementById('select-format') || document.querySelector('input[name="format"]');
|
|
190
|
+
|
|
191
|
+
var body = new URLSearchParams({
|
|
192
|
+
content: content,
|
|
193
|
+
title: (document.getElementById('i-title') || {}).value || '',
|
|
194
|
+
date: (document.getElementById('i-date') || {}).value || '',
|
|
195
|
+
tags: (document.getElementById('i-tags') || {}).value || '',
|
|
196
|
+
layout: layoutEl ? layoutEl.value : '',
|
|
197
|
+
format: formatEl ? formatEl.value : 'md'
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
fetch('/ajax/preview', { method: 'POST', body: body })
|
|
201
|
+
.then(function(r) { return r.text(); })
|
|
202
|
+
.then(function(url) {
|
|
203
|
+
document.getElementById('preview-iframe').src = url;
|
|
204
|
+
panel.classList.remove('d-none');
|
|
205
|
+
wrapper.classList.add('preview-active');
|
|
206
|
+
document.querySelector('main').classList.add('preview-active-main');
|
|
207
|
+
document.getElementById('waiting').style.display = 'none';
|
|
208
|
+
setTimeout(function() {
|
|
209
|
+
if (window.myCodeMirror) window.myCodeMirror.refresh();
|
|
210
|
+
}, 100);
|
|
211
|
+
})
|
|
212
|
+
.catch(function() {
|
|
213
|
+
document.getElementById('waiting').style.display = 'none';
|
|
214
|
+
});
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (e.target.closest('#btn-refresh-preview')) {
|
|
219
|
+
e.preventDefault();
|
|
220
|
+
document.getElementById('btn-preview').click();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (e.target.closest('#btn-close-preview')) {
|
|
225
|
+
e.preventDefault();
|
|
226
|
+
var wrapper = document.getElementById('preview-wrapper');
|
|
227
|
+
var panel = document.getElementById('preview-panel');
|
|
228
|
+
panel.classList.add('d-none');
|
|
229
|
+
wrapper.classList.remove('preview-active');
|
|
230
|
+
document.querySelector('main').classList.remove('preview-active-main');
|
|
231
|
+
setTimeout(function() {
|
|
232
|
+
if (window.myCodeMirror) window.myCodeMirror.refresh();
|
|
233
|
+
}, 100);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
158
238
|
</script>
|
|
239
|
+
</div><!-- /editor-panel -->
|
|
240
|
+
|
|
241
|
+
<div id="preview-panel" class="d-none">
|
|
242
|
+
<div class="preview-panel-header d-flex align-items-center justify-content-between p-2 bg-light border-bottom">
|
|
243
|
+
<span><i class="fas fa-eye"></i> <%= CGI.escapeHTML t.editor_preview %></span>
|
|
244
|
+
<div>
|
|
245
|
+
<button type="button" class="btn btn-sm btn-outline-secondary" id="btn-refresh-preview" title="<%= CGI.escapeHTML t.preview_refresh %>">
|
|
246
|
+
<i class="fas fa-sync-alt"></i>
|
|
247
|
+
</button>
|
|
248
|
+
<button type="button" class="btn btn-sm btn-outline-danger" id="btn-close-preview" title="<%= CGI.escapeHTML t.preview_close %>">
|
|
249
|
+
<i class="fas fa-times"></i>
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
<iframe id="preview-iframe" src="about:blank"></iframe>
|
|
254
|
+
</div>
|
|
255
|
+
</div><!-- /preview-wrapper -->
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
<h2><%=
|
|
1
|
+
<h2><%= CGI.escapeHTML t.send(@type_file).capitalize %> <a href="/<%= @type_file %>/new" class="btn btn-secondary btn-sm"><i class="fas fa-plus"></i> <%= CGI.escapeHTML t.new.capitalize %></a></h2>
|
|
2
2
|
|
|
3
3
|
<div class="table-responsive">
|
|
4
|
-
<table class="table table-striped table-sm">
|
|
4
|
+
<table class="table table-striped table-sm table-bordered">
|
|
5
5
|
<tr>
|
|
6
6
|
<th>
|
|
7
|
-
<%=
|
|
7
|
+
<%= CGI.escapeHTML t.file.capitalize %>
|
|
8
8
|
</th>
|
|
9
9
|
<th>
|
|
10
|
-
<%=
|
|
10
|
+
<%= CGI.escapeHTML t.edit.capitalize %>
|
|
11
11
|
</th>
|
|
12
12
|
<th>
|
|
13
|
-
<%=
|
|
13
|
+
<%= CGI.escapeHTML t.delete.capitalize %>
|
|
14
14
|
</th>
|
|
15
15
|
</tr>
|
|
16
16
|
<% @files.each do |f| %>
|
|
17
|
-
<% edit_path = "/#{@type_file}?file=#{f}" %>
|
|
17
|
+
<% edit_path = "/#{@type_file}?file=#{CGI.escape(f)}" %>
|
|
18
18
|
<tr>
|
|
19
19
|
<td>
|
|
20
20
|
<a href="<%= edit_path %>" class="link-dark">
|
|
21
|
-
<%= f.gsub(File.join(Dir.pwd, ''),'') %>
|
|
21
|
+
<%= CGI.escapeHTML(f.gsub(File.join(Dir.pwd, ''),'')) %>
|
|
22
22
|
</a>
|
|
23
23
|
</td>
|
|
24
24
|
<td>
|
|
25
|
-
<a href="<%= edit_path %>" class="btn btn-default"><i class="fa fa-edit" title="<%=
|
|
25
|
+
<a href="<%= edit_path %>" class="btn btn-default"><i class="fa fa-edit" title="<%= CGI.escapeHTML t.edit.capitalize %>"></i></a>
|
|
26
26
|
</td>
|
|
27
27
|
<td>
|
|
28
|
-
<form method="post" action="/<%= @type_file %>/delete" class="inline form-confirm" data-confirm="<%=
|
|
28
|
+
<form method="post" action="/<%= @type_file %>/delete" class="inline form-confirm" data-confirm="<%= CGI.escapeHTML t.are_you_sure %>">
|
|
29
29
|
<input type="hidden" name="file" value="<%= f %>">
|
|
30
|
-
<button type="submit" class="btn btn-default"><i class="fa fa-trash" title="<%=
|
|
30
|
+
<button type="submit" class="btn btn-default"><i class="fa fa-trash" title="<%= CGI.escapeHTML t.delete.capitalize %>"></i></button>
|
|
31
31
|
</form>
|
|
32
32
|
</td>
|
|
33
33
|
</tr>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<h2><i class="fa-solid fa-magnifying-glass"></i> <%= CGI.escapeHTML t.global_search.capitalize %></h2>
|
|
2
|
+
|
|
3
|
+
<form action="/search" method="get" class="mb-4">
|
|
4
|
+
<div class="input-group">
|
|
5
|
+
<input type="text" name="q" value="<%= CGI.escapeHTML(@query) %>" class="form-control" placeholder="<%= CGI.escapeHTML t.global_search_placeholder %>" autofocus>
|
|
6
|
+
<button class="btn btn-primary" type="submit"><%= CGI.escapeHTML t.search.capitalize %></button>
|
|
7
|
+
</div>
|
|
8
|
+
</form>
|
|
9
|
+
|
|
10
|
+
<% if @query.length >= 2 %>
|
|
11
|
+
<p class="text-muted"><%= @results.size %> <%= CGI.escapeHTML t.global_search_results_for %> "<%= CGI.escapeHTML(@query) %>"</p>
|
|
12
|
+
|
|
13
|
+
<% if @results.empty? %>
|
|
14
|
+
<p><%= CGI.escapeHTML t.global_search_no_results.capitalize %></p>
|
|
15
|
+
<% else %>
|
|
16
|
+
<% type_icons = { 'posts' => 'fa-file-lines', 'pages' => 'fa-file', 'drafts' => 'fa-file-pen', 'files' => 'fa-copy' } %>
|
|
17
|
+
<% @results.group_by { |r| r[:type] }.each do |type, results| %>
|
|
18
|
+
<h5 class="mt-4 mb-3"><i class="fa-solid <%= type_icons[type] || 'fa-file' %>"></i> <%= CGI.escapeHTML t.send(type).capitalize %></h5>
|
|
19
|
+
<div class="list-group mb-3">
|
|
20
|
+
<% results.each do |r| %>
|
|
21
|
+
<a href="<%= r[:edit_url] %>" class="list-group-item list-group-item-action">
|
|
22
|
+
<div class="d-flex justify-content-between align-items-start">
|
|
23
|
+
<div>
|
|
24
|
+
<strong><%= CGI.escapeHTML(r[:title].to_s) %></strong>
|
|
25
|
+
<br><small class="text-muted"><%= CGI.escapeHTML(r[:relative]) %></small>
|
|
26
|
+
<% if r[:tags] && !r[:tags].empty? %>
|
|
27
|
+
<br>
|
|
28
|
+
<% r[:tags].split(',').each do |tag| %>
|
|
29
|
+
<span class="badge bg-secondary"><%= CGI.escapeHTML(tag.strip) %></span>
|
|
30
|
+
<% end %>
|
|
31
|
+
<% end %>
|
|
32
|
+
<% if r[:excerpt] %>
|
|
33
|
+
<br><small class="text-muted fst-italic"><%= CGI.escapeHTML(r[:excerpt]) %></small>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</a>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|
|
40
|
+
<% end %>
|
|
41
|
+
<% end %>
|
|
42
|
+
<% end %>
|
|
@@ -33,16 +33,16 @@
|
|
|
33
33
|
<%= t.pictures_has_been_uploaded.capitalize %> : <%= @filenames.join(', ') %>
|
|
34
34
|
<% end %>
|
|
35
35
|
|
|
36
|
-
<form enctype="multipart/form-data" method="post" action="/upload_image"
|
|
37
|
-
<div class="
|
|
36
|
+
<form enctype="multipart/form-data" method="post" action="/upload_image">
|
|
37
|
+
<div class="input-group mb-3">
|
|
38
38
|
<input type="file" name="files[]" multiple class="form-control">
|
|
39
|
-
</div>
|
|
40
|
-
<div class="col-2">
|
|
41
39
|
<button class="btn btn-primary"><%= t.upload.capitalize %></button>
|
|
42
40
|
</div>
|
|
41
|
+
|
|
42
|
+
<a class="btn btn-secondary btn-return-to-editor"><%= t.quit.capitalize %></a>
|
|
43
43
|
</form>
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
48
48
|
</body>
|