dokno 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/app/assets/javascripts/dokno.js +29 -32
- data/app/controllers/dokno/articles_controller.rb +6 -6
- data/app/models/dokno/article.rb +1 -0
- data/app/models/dokno/category.rb +3 -2
- data/app/views/dokno/_article_formatting.html.erb +12 -12
- data/app/views/dokno/articles/_article_form.html.erb +3 -3
- data/app/views/dokno/articles/show.html.erb +31 -36
- data/app/views/dokno/categories/index.html.erb +16 -31
- data/app/views/layouts/dokno/application.html.erb +12 -8
- data/app/views/partials/_category_header.html.erb +29 -0
- data/app/views/partials/_form_errors.html.erb +0 -1
- data/app/views/partials/_logs.html.erb +1 -1
- data/config/routes.rb +0 -1
- data/lib/dokno/version.rb +1 -1
- metadata +80 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6832c4cb6bd12af77ec2e917a511ff8e1e321ef075fea55d3fda293d215086d
|
4
|
+
data.tar.gz: 031e5cd22170d331739f92304ee740804703cb692839c92b8ddea8dc7aded424
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31cc72ec145aadaa3aaa34be3d650387b35c905799b5bf19d38a0effed21db7e51dec651c12e252ea87670a17b6f5439e26cbbacb1b8887dca043dc0eb7602da
|
7
|
+
data.tar.gz: 7dafaa4a7431c3216234a2de4551f749874ffb2aaf8f25ec0002e544828002581a74f648fdc8139bb6406eb8fde28a8694600364050de9b0c38b1ad22795a306
|
data/README.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
|
+
const dokno__search_hotkey_listener = function(e) {
|
2
|
+
if (e.key === '/') { handleSearchHotKey(); }
|
3
|
+
}
|
4
|
+
|
5
|
+
function handleSearchHotKey() {
|
6
|
+
const search_input = elem('input#search_term');
|
7
|
+
search_input.focus();
|
8
|
+
search_input.select();
|
9
|
+
}
|
10
|
+
|
11
|
+
function enableSearchHotkey() {
|
12
|
+
document.addEventListener('keyup', dokno__search_hotkey_listener, false);
|
13
|
+
}
|
14
|
+
|
15
|
+
function disableSearchHotkey() {
|
16
|
+
document.removeEventListener('keyup', dokno__search_hotkey_listener, false);
|
17
|
+
}
|
18
|
+
|
1
19
|
function copyToClipboard(text) {
|
2
|
-
window.prompt('Copy to clipboard: CTRL+C, Enter', text);
|
20
|
+
window.prompt('Copy to clipboard: CTRL + C, Enter', text);
|
3
21
|
}
|
4
22
|
|
5
23
|
function elem(selector) {
|
@@ -22,19 +40,20 @@ function selectOption(id, value) {
|
|
22
40
|
}
|
23
41
|
}
|
24
42
|
|
25
|
-
function
|
43
|
+
function applyCategoryCriteria(category_code, term, order) {
|
26
44
|
goToPage(dokno__base_path + category_code + '?search_term=' + term + '&order=' + order);
|
27
45
|
}
|
28
46
|
|
29
|
-
function search(term, order) {
|
30
|
-
goToPage('?search_term=' + term + '&order=' + order);
|
31
|
-
}
|
32
|
-
|
33
47
|
function goToPage(url) {
|
34
48
|
var param_join = url.indexOf('?') >= 0 ? '&' : '?';
|
35
49
|
location.href=url + param_join + '_=' + Math.round(new Date().getTime());
|
36
50
|
}
|
37
51
|
|
52
|
+
function reloadPage() {
|
53
|
+
window.onbeforeunload = function () { window.scrollTo(0, 0); }
|
54
|
+
location.reload();
|
55
|
+
}
|
56
|
+
|
38
57
|
function sendRequest(url, data, callback, method) {
|
39
58
|
const request = new XMLHttpRequest();
|
40
59
|
request.open(method, url, true);
|
@@ -55,23 +74,13 @@ function sendRequest(url, data, callback, method) {
|
|
55
74
|
request.send(JSON.stringify(data));
|
56
75
|
}
|
57
76
|
|
58
|
-
function
|
59
|
-
const callback = function(_data) {
|
60
|
-
elem('button#article-deactivate-button').classList.add('hidden');
|
61
|
-
elem('div#article-deprecated-alert').classList.remove('hidden');
|
62
|
-
elem('button#article-activate-button').classList.remove('hidden');
|
63
|
-
reloadLogs();
|
64
|
-
}
|
77
|
+
function deactivateArticle(slug) {
|
78
|
+
const callback = function(_data) { reloadPage(); }
|
65
79
|
sendRequest(dokno__base_path + 'article_status', { slug: slug, active: false }, callback, 'POST');
|
66
80
|
}
|
67
81
|
|
68
|
-
function
|
69
|
-
const callback = function(_data) {
|
70
|
-
elem('button#article-activate-button').classList.add('hidden');
|
71
|
-
elem('div#article-deprecated-alert').classList.add('hidden');
|
72
|
-
elem('button#article-deactivate-button').classList.remove('hidden');
|
73
|
-
reloadLogs();
|
74
|
-
}
|
82
|
+
function activateArticle(slug) {
|
83
|
+
const callback = function(_data) { reloadPage(); }
|
75
84
|
sendRequest(dokno__base_path + 'article_status', { slug: slug, active: true }, callback, 'POST');
|
76
85
|
}
|
77
86
|
|
@@ -148,18 +157,6 @@ function toggleVisibility(selector_id) {
|
|
148
157
|
initIcons();
|
149
158
|
}
|
150
159
|
|
151
|
-
function reloadLogs() {
|
152
|
-
var $log_container = elem('div#dokno-article-log-container');
|
153
|
-
var category_id = $log_container.getAttribute('data-category-id');
|
154
|
-
var article_id = $log_container.getAttribute('data-article-id');
|
155
|
-
|
156
|
-
const callback = function(markup) {
|
157
|
-
elem('div#dokno-article-log-container').innerHTML = markup;
|
158
|
-
initIcons();
|
159
|
-
}
|
160
|
-
sendRequest(dokno__base_path + 'article_log', { category_id: category_id, article_id: article_id }, callback, 'POST');
|
161
|
-
}
|
162
|
-
|
163
160
|
// Pass containers_selector as class name (no prefix)
|
164
161
|
function highlightTerm(terms, containers_selector) {
|
165
162
|
var containers = elems(containers_selector);
|
@@ -8,7 +8,13 @@ module Dokno
|
|
8
8
|
|
9
9
|
def show
|
10
10
|
redirect_to root_path if @article.blank?
|
11
|
+
|
11
12
|
@search_term = params[:search_term]
|
13
|
+
@order = params[:order]
|
14
|
+
@category = Category.find_by(code: params[:cat_code].to_s.strip) if params[:cat_code].present?
|
15
|
+
@category = @article.categories.first if @category.blank?
|
16
|
+
|
17
|
+
flash.now[:yellow] = 'This article is no longer active' unless @article.active
|
12
18
|
end
|
13
19
|
|
14
20
|
def new
|
@@ -79,12 +85,6 @@ module Dokno
|
|
79
85
|
render json: {}, layout: false
|
80
86
|
end
|
81
87
|
|
82
|
-
# Ajax-fetched article change log
|
83
|
-
def article_log
|
84
|
-
render partial: '/partials/logs',
|
85
|
-
locals: { article: Article.find_by(id: params[:article_id].to_i) }, layout: false
|
86
|
-
end
|
87
|
-
|
88
88
|
private
|
89
89
|
|
90
90
|
def article_params
|
data/app/models/dokno/article.rb
CHANGED
@@ -18,6 +18,7 @@ module Dokno
|
|
18
18
|
before_save :log_changes
|
19
19
|
before_save :track_slug
|
20
20
|
|
21
|
+
scope :active, -> { where(active: true) }
|
21
22
|
scope :alpha_order, -> { order(active: :desc, title: :asc) }
|
22
23
|
scope :view_order, -> { order(active: :desc, views: :desc, title: :asc) }
|
23
24
|
scope :newest_order, -> { order(active: :desc, created_at: :desc, title: :asc) }
|
@@ -59,7 +59,7 @@ module Dokno
|
|
59
59
|
|
60
60
|
# Used to invalidate the fragment cache of the hierarchical category select options
|
61
61
|
def self.cache_key
|
62
|
-
maximum :updated_at
|
62
|
+
[maximum(:updated_at), Article.maximum(:updated_at)].max
|
63
63
|
end
|
64
64
|
|
65
65
|
# The given Category and all child Categories. Useful for filtering associated articles.
|
@@ -109,7 +109,8 @@ module Dokno
|
|
109
109
|
return '' if category.id == exclude_category_id
|
110
110
|
|
111
111
|
selected = selected_category_codes&.include?(category.code)
|
112
|
-
|
112
|
+
article_count = category.articles_in_branch.size
|
113
|
+
%(<option value="#{category.code}" #{'selected="selected"' if selected}>#{(' ' * level)}#{category.name}#{' (' + article_count.to_s + ')' if article_count.positive?}</option>)
|
113
114
|
end
|
114
115
|
|
115
116
|
# Never allow setting of parent to self
|
@@ -2,8 +2,8 @@
|
|
2
2
|
/* Article formatting */
|
3
3
|
.dokno-article-content-markup {
|
4
4
|
font-weight: 400;
|
5
|
-
line-height: 1.
|
6
|
-
font-size:
|
5
|
+
line-height: 1.75em;
|
6
|
+
font-size: 1em;
|
7
7
|
}
|
8
8
|
|
9
9
|
.dokno-article-content-markup code {
|
@@ -23,7 +23,7 @@
|
|
23
23
|
.dokno-article-content-markup ol,
|
24
24
|
.dokno-article-content-markup hr,
|
25
25
|
.dokno-article-content-markup table {
|
26
|
-
margin-bottom: 1.
|
26
|
+
margin-bottom: 1.25em;
|
27
27
|
}
|
28
28
|
|
29
29
|
.dokno-article-content-markup h1,
|
@@ -32,28 +32,28 @@
|
|
32
32
|
.dokno-article-content-markup h4,
|
33
33
|
.dokno-article-content-markup h5,
|
34
34
|
.dokno-article-content-markup h6 {
|
35
|
-
margin-bottom: 1.
|
35
|
+
margin-bottom: 1.25em;
|
36
36
|
font-weight: 600;
|
37
37
|
}
|
38
38
|
|
39
39
|
.dokno-article-content-markup h1 {
|
40
|
-
font-size: 1.
|
40
|
+
font-size: 1.625em;
|
41
41
|
}
|
42
42
|
|
43
43
|
.dokno-article-content-markup h2 {
|
44
|
-
font-size: 1.
|
44
|
+
font-size: 1.25em;
|
45
45
|
}
|
46
46
|
|
47
47
|
.dokno-article-content-markup h3,
|
48
48
|
.dokno-article-content-markup h4,
|
49
49
|
.dokno-article-content-markup h5,
|
50
50
|
.dokno-article-content-markup h6 {
|
51
|
-
font-size:
|
51
|
+
font-size: 1em;
|
52
52
|
}
|
53
53
|
|
54
54
|
.dokno-article-content-markup blockquote {
|
55
55
|
border-left: 4px solid #edf2f7;
|
56
|
-
padding-left: 1.
|
56
|
+
padding-left: 1.25em;
|
57
57
|
}
|
58
58
|
|
59
59
|
.dokno-article-content-markup ul,
|
@@ -75,10 +75,10 @@
|
|
75
75
|
|
76
76
|
.dokno-article-content-markup table th,
|
77
77
|
.dokno-article-content-markup table td {
|
78
|
-
padding-left:
|
79
|
-
padding-right:
|
80
|
-
padding-top: 0.
|
81
|
-
padding-bottom: 0.
|
78
|
+
padding-left: 1em;
|
79
|
+
padding-right: 1em;
|
80
|
+
padding-top: 0.5em;
|
81
|
+
padding-bottom: 0.5em;
|
82
82
|
font-weight: normal;
|
83
83
|
}
|
84
84
|
|
@@ -47,14 +47,14 @@
|
|
47
47
|
<a id="markdown_write_link" href="javascript:;" onclick="writeArticleToggle();" class="float-right hidden"><i data-feather="pen-tool" class="inline"></i> Write</a>
|
48
48
|
<a id="markdown_preview_link" href="javascript:;" onclick="previewArticleToggle();" class="float-right"><i data-feather="eye" class="inline"></i> Preview</a>
|
49
49
|
</div>
|
50
|
-
<textarea placeholder="Full article content" name="markdown" id="markdown" class="rounded text-xl shadow-inner bg-gray-100 p-3 mt-2 w-full" rows="
|
50
|
+
<textarea placeholder="Full article content" name="markdown" id="markdown" class="rounded text-xl shadow-inner bg-gray-100 p-3 mt-2 w-full" rows="20"><%= article.persisted? ? article.markdown : (article.markdown.presence || @template) %></textarea>
|
51
51
|
<div id="markdown_preview" class="dokno-article-content-markup hidden text-lg overflow-hidden overflow-y-auto rounded p-10 mt-2 bg-gray-100 shadow-inner"></div>
|
52
52
|
<div class="text-gray-500 mt-2">Detailed documentation of the described topic. Basic HTML & <a target="_blank" href="https://commonmark.org/help/" title="Markdown formatting examples">markdown</a> OK.</div>
|
53
53
|
</div>
|
54
54
|
|
55
|
-
<div class="mt-10">
|
55
|
+
<div class="mt-10 text-right">
|
56
|
+
<span class="text-lg mr-5"><a class="no-underline" href="<%= article.persisted? ? article_path(article.slug) : root_path %>">Cancel</a></span>
|
56
57
|
<button type="submit" class="bg-gray-700 text-gray-300 hover:bg-gray-900 hover:text-white rounded py-2 px-3 font-bold"><i data-feather="check" class="inline h-5"></i> SAVE ARTICLE</button>
|
57
|
-
<span class="text-lg ml-5"><a class="no-underline" href="<%= article.persisted? ? article_path(article.slug) : root_path %>">Cancel</a></span>
|
58
58
|
</div>
|
59
59
|
|
60
60
|
</section>
|
@@ -1,30 +1,25 @@
|
|
1
1
|
<%= render 'dokno/article_formatting' %>
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
<div
|
6
|
-
|
7
|
-
|
8
|
-
<% end %>
|
9
|
-
</div>
|
10
|
-
<% end %>
|
3
|
+
<% if @category.present? %>
|
4
|
+
<div class="no-print text-gray-500 mb-5">
|
5
|
+
<div>Category: <a href="<%= article_index_path(@category.code) %>?search_term=<%= CGI.escape(@search_term.to_s) %>&order=<%= @order %>"><%= @category.breadcrumb %></a></div>
|
6
|
+
</div>
|
7
|
+
<% end %>
|
11
8
|
|
9
|
+
<%= render 'partials/category_header' %>
|
10
|
+
|
11
|
+
<div class="my-10 no-print"><hr /></div>
|
12
|
+
|
13
|
+
<section>
|
12
14
|
<div class="flex">
|
13
15
|
<div id="dokno-article-sidebar" class="w-2/5 pr-10">
|
14
|
-
<
|
15
|
-
<i data-feather="alert-circle" class="inline-block mr-2"></i> This article is no longer active
|
16
|
-
</div>
|
17
|
-
|
18
|
-
<h1 class="dokno-article-content-highlight text-4xl mb-10 leading-tight font-light"><%= @article.title %></h1>
|
16
|
+
<h1 class="dokno-article-content-highlight text-4xl mb-8 leading-tight font-light"><%= @article.title %></h1>
|
19
17
|
|
20
18
|
<div>
|
21
|
-
<div class="mb-
|
22
|
-
<button title="
|
23
|
-
<button title="
|
24
|
-
|
25
|
-
<% if can_edit? %>
|
26
|
-
<button title="Edit article" class="bg-blue-900 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-xs" onclick="location.href='<%= edit_article_path(@article.slug) %>';"><i data-feather="edit" class="inline h-4"></i> EDIT THIS</button>
|
27
|
-
<% end %>
|
19
|
+
<div class="mb-8 no-print">
|
20
|
+
<button title="Copy link" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 mr-2 py-2 px-3 font-bold text-sm" onclick="copyToClipboard('<%= @article.permalink(request.base_url) %>');"><i data-feather="clipboard" class="inline h-5"></i> COPY</button>
|
21
|
+
<button title="Email article" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 mr-2 py-2 px-3 font-bold text-sm" onclick="window.open('mailto:?subject=<%= CGI.escape(@article.title.to_s) %>&body=<%= CGI.escape(article_url(@article.slug)) %>');"><i data-feather="send" class="inline h-5"></i> EMAIL</button>
|
22
|
+
<button title="Print article" class="bg-gray-600 text-gray-300 hover:text-white rounded my-2 py-2 px-3 font-bold text-sm" onclick="window.print();"><i data-feather="printer" class="inline h-5"></i> PRINT</button>
|
28
23
|
</div>
|
29
24
|
|
30
25
|
<div class="flex">
|
@@ -93,12 +88,11 @@
|
|
93
88
|
</div>
|
94
89
|
<% end %>
|
95
90
|
|
96
|
-
<% if @article.
|
91
|
+
<% if (category_name_list = @article.category_name_list(context_category_id: @category&.id)).present? %>
|
97
92
|
<div class="mt-5 flex no-print">
|
98
93
|
<div class="no-print w-8"><i data-feather="folder" class="inline-block h-5"></i></div>
|
99
94
|
<div class="w-full">
|
100
|
-
<%= '
|
101
|
-
<%= @article.category_name_list.split(':').last.html_safe %>
|
95
|
+
<%= category_name_list.sub(':', ':<br />').html_safe %>
|
102
96
|
</div>
|
103
97
|
</div>
|
104
98
|
<% end %>
|
@@ -118,21 +112,22 @@
|
|
118
112
|
<% if @article.summary.blank? && @article.markdown.blank? %>
|
119
113
|
<div class="mb-10">No content</div>
|
120
114
|
<% end %>
|
121
|
-
|
122
|
-
<% if can_edit? %>
|
123
|
-
<div class="no-print">
|
124
|
-
<hr class="mt-5" />
|
125
|
-
<div class="mt-10 text-right">
|
126
|
-
<button title="Deactivate article" id="article-deactivate-button" class="bg-yellow-700 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs <% if !@article.active %>hidden<% end %>" onclick="deactiveArticle('<%= @article.slug %>');"><i data-feather="sunset" class="inline h-4"></i> DEACTIVATE THIS</button>
|
127
|
-
<button title="Re-activate article" id="article-activate-button" class="bg-green-700 text-gray-300 hover:text-white rounded mr-3 py-2 px-3 font-bold text-xs <% if @article.active %>hidden<% end %>" onclick="activeArticle('<%= @article.slug %>');"><i data-feather="sunrise" class="inline h-4"></i> RE-ACTIVATE THIS</button>
|
128
|
-
<button title="Permanently delete article" class="bg-red-700 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-xs" onclick="deleteArticle('<%= @article.id %>');"><i data-feather="trash" class="inline h-4"></i> DELETE THIS</button>
|
129
|
-
</div>
|
130
|
-
</div>
|
131
|
-
<% end %>
|
132
115
|
</div>
|
133
116
|
</div>
|
134
117
|
</section>
|
135
118
|
|
136
|
-
<% if
|
137
|
-
<
|
119
|
+
<% if can_edit? %>
|
120
|
+
<div class="no-print">
|
121
|
+
<hr class="mt-5 mb-10" />
|
122
|
+
<div class="text-right">
|
123
|
+
<button title="Edit article" class="bg-blue-900 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-sm" onclick="location.href='<%= edit_article_path(@article.slug) %>';"><i data-feather="edit" class="inline h-5"></i> EDIT</button>
|
124
|
+
|
125
|
+
<% if @article.active %>
|
126
|
+
<button title="Deactivate article" id="article-deactivate-button" class="bg-yellow-700 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-base" onclick="deactivateArticle('<%= @article.slug %>');"><i data-feather="sunset" class="inline h-5"></i> DEACTIVATE</button>
|
127
|
+
<% else %>
|
128
|
+
<button title="Re-activate article" id="article-activate-button" class="bg-green-700 text-gray-300 hover:text-white rounded mr-5 py-2 px-3 font-bold text-base" onclick="activateArticle('<%= @article.slug %>');"><i data-feather="sunrise" class="inline h-5"></i> RE-ACTIVATE</button>
|
129
|
+
<% end %>
|
130
|
+
<button title="Permanently delete article" class="bg-red-700 text-gray-300 hover:text-white rounded py-2 px-3 font-bold text-base" onclick="deleteArticle('<%= @article.id %>');"><i data-feather="trash" class="inline h-5"></i> DELETE</button>
|
131
|
+
</div>
|
132
|
+
</div>
|
138
133
|
<% end %>
|
@@ -4,23 +4,9 @@
|
|
4
4
|
</div>
|
5
5
|
<% end %>
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<select aria-label="Category" name="category" id="category" size="1" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full max-w-full" onchange="changeCategory(this.value, elem('#search_term').value, '<%= @order %>');">
|
12
|
-
<option value="">Select a category</option>
|
13
|
-
<% cache Dokno::Category do %>
|
14
|
-
<%= Dokno::Category.select_option_markup.html_safe %>
|
15
|
-
<% end %>
|
16
|
-
</select>
|
17
|
-
|
18
|
-
</div>
|
19
|
-
<% end %>
|
20
|
-
<div class="w-<%= Dokno::Category.exists? ? '1/2 pl-5' : 'full' %>">
|
21
|
-
<input onsearch="search(this.value, '<%= @order %>');" placeholder="Search article content, titles, and slugs" type="search" name="search_term" id="search_term" value="<%= @search_term %>" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full" />
|
22
|
-
</div>
|
23
|
-
</div>
|
7
|
+
<% if Dokno::Category.exists? || Dokno::Article.exists? %>
|
8
|
+
<%= render 'partials/category_header' %>
|
9
|
+
<% end %>
|
24
10
|
|
25
11
|
<% if @articles.blank? %>
|
26
12
|
|
@@ -46,10 +32,10 @@
|
|
46
32
|
</div>
|
47
33
|
<div class="w-1/3 text-right">
|
48
34
|
<i data-feather="corner-right-down" class="h-5 inline-block" title="Sort order"></i>
|
49
|
-
<a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'updated' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=updated">Updated</a>
|
50
|
-
<a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'newest' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=newest">Newest</a>
|
51
|
-
<a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'views' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=views">Views</a>
|
52
|
-
<a class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'alpha' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=alpha">Title</a>
|
35
|
+
<a id="dokno-order-link-updated" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'updated' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=updated">Updated</a>
|
36
|
+
<a id="dokno-order-link-newest" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'newest' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=newest">Newest</a>
|
37
|
+
<a id="dokno-order-link-views" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'views' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=views">Views</a>
|
38
|
+
<a id="dokno-order-link-alpha" class="ml-3 pb-1 <%= 'border-b-2 border-blue-900' if @order == 'alpha' %>" href="?search_term=<%= CGI.escape @search_term.to_s %>&order=alpha">Title</a>
|
53
39
|
</div>
|
54
40
|
</div>
|
55
41
|
|
@@ -60,7 +46,7 @@
|
|
60
46
|
<div class="flex">
|
61
47
|
<div class="no-print w-10 text-gray-300"><i data-feather="chevron-right" class="inline-block"></i></div>
|
62
48
|
<div class="w-full">
|
63
|
-
<a class="" href="<%= article_path article.slug %>?search_term=<%= @search_term %>" title="View article"><%= article.title %></a>
|
49
|
+
<a class="dokno-article-title <% unless article.active %>text-gray-500 italic<% end %>" href="<%= article_path article.slug %>?search_term=<%= @search_term %>&cat_code=<%= @category&.code %>&order=<%= @order %>" title="View article"><%= article.title %></a>
|
64
50
|
</div>
|
65
51
|
</div>
|
66
52
|
</div>
|
@@ -71,10 +57,14 @@
|
|
71
57
|
</div>
|
72
58
|
<% end %>
|
73
59
|
|
74
|
-
<
|
60
|
+
<div class="dokno-article-content-highlight mb-2"><%= article.summary.presence || 'No summary provided' %></div>
|
61
|
+
|
62
|
+
<div class="text-base text-gray-500">
|
63
|
+
<%= article.category_name_list(context_category_id: @category&.id, order: @order, search_term: @search_term) %>
|
64
|
+
</div>
|
75
65
|
|
76
66
|
<% unless @order == 'alpha' %>
|
77
|
-
<div class="text-base
|
67
|
+
<div class="text-base">
|
78
68
|
<% if @order == 'views' %>
|
79
69
|
<div class="text-gray-500">Viewed <%= number_with_delimiter(article.views, delimiter: ',') %> <%= 'time'.pluralize(article.views) %></div>
|
80
70
|
<% elsif @order == 'updated' %>
|
@@ -97,11 +87,6 @@
|
|
97
87
|
</div>
|
98
88
|
<% end %>
|
99
89
|
|
100
|
-
|
101
|
-
|
102
|
-
selectOption('category', '<%= j @category&.code %>');
|
103
|
-
</script>
|
104
|
-
|
105
|
-
<% if @search_term.present? %>
|
106
|
-
<script> highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight'); </script>
|
90
|
+
<% if @search_term.present? && @articles.blank? %>
|
91
|
+
<script> handleSearchHotKey(); </script>
|
107
92
|
<% end %>
|
@@ -12,7 +12,7 @@
|
|
12
12
|
var dokno__base_path = '<%= root_path %>';
|
13
13
|
</script>
|
14
14
|
</head>
|
15
|
-
<body class="bg-white font-sans font-light subpixel-antialiased">
|
15
|
+
<body class="bg-white font-sans font-light subpixel-antialiased text-lg">
|
16
16
|
|
17
17
|
<nav id="dokno-nav-container" class="bg-blue-900 text-white py-10 px-16 text-lg">
|
18
18
|
<div class="flex items-center m-auto w-full max-w-screen-xl">
|
@@ -40,6 +40,13 @@
|
|
40
40
|
</div>
|
41
41
|
</nav>
|
42
42
|
|
43
|
+
<% flash.each do |color, msg| %>
|
44
|
+
<div class="bg-<%= color %>-700 text-lg text-white font-base py-10 px-16">
|
45
|
+
<i data-feather="<%= (color == 'green' ? 'check-circle' : (color == 'yellow' ? 'alert-circle' : 'x-circle')) %>" class="inline mr-2"></i>
|
46
|
+
<%= msg %>
|
47
|
+
</div>
|
48
|
+
<% end %>
|
49
|
+
|
43
50
|
<main class="py-10 px-16">
|
44
51
|
<% if @article.blank? && (@category.blank? || @search_term.present?) %>
|
45
52
|
<div class="text-center m-auto mb-10 w-full max-w-screen-xl">
|
@@ -63,13 +70,6 @@
|
|
63
70
|
<% end %>
|
64
71
|
|
65
72
|
<div id="dokno-content-container" class="w-full max-w-screen-xl m-auto print-this">
|
66
|
-
<% flash.each do |color, msg| %>
|
67
|
-
<div class="bg-<%= color %>-700 p-4 mb-5 rounded text-lg border-t-4 border-<%= color %>-900 text-white font-base">
|
68
|
-
<i data-feather="<%= (color == 'green' ? 'check-circle' : (color == 'yellow' ? 'alert-circle' : 'x-circle')) %>" class="inline mr-2"></i>
|
69
|
-
<%= msg %>
|
70
|
-
</div>
|
71
|
-
<% end %>
|
72
|
-
|
73
73
|
<%= yield %>
|
74
74
|
</div>
|
75
75
|
</main>
|
@@ -101,5 +101,9 @@
|
|
101
101
|
</footer>
|
102
102
|
|
103
103
|
<%= javascript_include_tag 'init' %>
|
104
|
+
|
105
|
+
<% if @search_term.present? %>
|
106
|
+
<script>highlightTerm(['<%= j @search_term.strip %>'], 'dokno-article-content-highlight');</script>
|
107
|
+
<% end %>
|
104
108
|
</body>
|
105
109
|
</html>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="no-print flex items-center mb-10">
|
2
|
+
<% if Dokno::Category.exists? %>
|
3
|
+
<div class="w-1/2 pr-5">
|
4
|
+
<select aria-label="Category" name="category" id="category" size="1" class="rounded text-xl shadow-inner bg-gray-100 p-2 w-full max-w-full" onchange="applyCategoryCriteria(this.value, elem('#search_term').value, '<%= @order %>');">
|
5
|
+
<option value="">Uncategorized</option>
|
6
|
+
|
7
|
+
<optgroup label="Categories">
|
8
|
+
<% cache Dokno::Category do %>
|
9
|
+
<%= Dokno::Category.select_option_markup.html_safe %>
|
10
|
+
<% end %>
|
11
|
+
</optgroup>
|
12
|
+
</select>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% if Dokno::Article.exists? %>
|
17
|
+
<div class="relative w-<%= Dokno::Category.exists? ? '1/2 pl-5' : 'full' %>">
|
18
|
+
<i data-feather="search" class="absolute ml-4 mt-3 inline-block text-gray-300" title="Search"></i>
|
19
|
+
<input title="Press / to search" onsearch="applyCategoryCriteria('<%= @category&.code %>', this.value, '<%= @order %>');" onfocus="disableSearchHotkey();" onblur="enableSearchHotkey();" placeholder="Search<%= @category.present? ? ' under this category' : ', hotkey /' %>" type="search" name="search_term" id="search_term" value="<%= @search_term %>" class="pl-12 pr-8 py-2 rounded text-xl shadow-inner bg-gray-100 w-full" />
|
20
|
+
<% if @category.present? %><div title="Press / to search" class="absolute -ml-6 mt-2 inline-block text-gray-300 font-semibold">/</div><% end %>
|
21
|
+
</div>
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<script>
|
26
|
+
// Client-side select of cached select list
|
27
|
+
selectOption('category', '<%= j @category&.code %>');
|
28
|
+
enableSearchHotkey();
|
29
|
+
</script>
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<div class="py-10 px-16 text-gray-200 bg-gray-900">
|
3
3
|
<div class="w-full max-w-screen-xl m-auto">
|
4
4
|
<div class="text-xl text-gray-600 cursor-pointer" onclick="toggleVisibility('change-log');">
|
5
|
-
Change
|
5
|
+
Change history for this article
|
6
6
|
|
7
7
|
<div class="inline toggle-visibility-indicator-container change-log">
|
8
8
|
<i data-feather="chevron-left" class="inline toggle-visibility-indicator change-log"></i>
|
data/config/routes.rb
CHANGED
@@ -4,7 +4,6 @@ Dokno::Engine.routes.draw do
|
|
4
4
|
|
5
5
|
get '/(:cat_code)', to: 'categories#index', as: :article_index
|
6
6
|
get 'article_panel/(:slug)', to: 'articles#panel', as: :panel
|
7
|
-
post 'article_log', to: 'articles#article_log', as: :article_log
|
8
7
|
post 'article_preview', to: 'articles#preview', as: :preview
|
9
8
|
post 'article_status', to: 'articles#status', as: :status
|
10
9
|
root 'categories#index'
|
data/lib/dokno/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dokno
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Courtney Payne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-12-
|
11
|
+
date: 2020-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diffy
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bullet
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: capybara
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.34'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.34'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: database_cleaner-active_record
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +80,20 @@ dependencies:
|
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
82
|
version: '1.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faker
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.15'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '2.15'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: pg
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,6 +128,20 @@ dependencies:
|
|
86
128
|
- - "~>"
|
87
129
|
- !ruby/object:Gem::Version
|
88
130
|
version: '3.9'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: puma
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '5.1'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '5.1'
|
89
145
|
- !ruby/object:Gem::Dependency
|
90
146
|
name: rails
|
91
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -127,47 +183,59 @@ dependencies:
|
|
127
183
|
- !ruby/object:Gem::Version
|
128
184
|
version: 4.0.1
|
129
185
|
- !ruby/object:Gem::Dependency
|
130
|
-
name:
|
186
|
+
name: selenium-webdriver
|
131
187
|
requirement: !ruby/object:Gem::Requirement
|
132
188
|
requirements:
|
133
189
|
- - "~>"
|
134
190
|
- !ruby/object:Gem::Version
|
135
|
-
version:
|
191
|
+
version: '3.142'
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: 3.142.7
|
136
195
|
type: :development
|
137
196
|
prerelease: false
|
138
197
|
version_requirements: !ruby/object:Gem::Requirement
|
139
198
|
requirements:
|
140
199
|
- - "~>"
|
141
200
|
- !ruby/object:Gem::Version
|
142
|
-
version:
|
201
|
+
version: '3.142'
|
202
|
+
- - ">="
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: 3.142.7
|
143
205
|
- !ruby/object:Gem::Dependency
|
144
|
-
name:
|
206
|
+
name: simplecov
|
145
207
|
requirement: !ruby/object:Gem::Requirement
|
146
208
|
requirements:
|
147
209
|
- - "~>"
|
148
210
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
211
|
+
version: 0.19.1
|
150
212
|
type: :development
|
151
213
|
prerelease: false
|
152
214
|
version_requirements: !ruby/object:Gem::Requirement
|
153
215
|
requirements:
|
154
216
|
- - "~>"
|
155
217
|
- !ruby/object:Gem::Version
|
156
|
-
version:
|
218
|
+
version: 0.19.1
|
157
219
|
- !ruby/object:Gem::Dependency
|
158
|
-
name:
|
220
|
+
name: webdrivers
|
159
221
|
requirement: !ruby/object:Gem::Requirement
|
160
222
|
requirements:
|
161
223
|
- - "~>"
|
162
224
|
- !ruby/object:Gem::Version
|
163
|
-
version: '
|
225
|
+
version: '4.4'
|
226
|
+
- - ">="
|
227
|
+
- !ruby/object:Gem::Version
|
228
|
+
version: 4.4.1
|
164
229
|
type: :development
|
165
230
|
prerelease: false
|
166
231
|
version_requirements: !ruby/object:Gem::Requirement
|
167
232
|
requirements:
|
168
233
|
- - "~>"
|
169
234
|
- !ruby/object:Gem::Version
|
170
|
-
version: '
|
235
|
+
version: '4.4'
|
236
|
+
- - ">="
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
version: 4.4.1
|
171
239
|
description: Dokno allows you to easily mount a self-contained knowledgebase / wiki
|
172
240
|
/ help system to your Rails app.
|
173
241
|
email:
|
@@ -210,6 +278,7 @@ files:
|
|
210
278
|
- app/views/dokno/categories/index.html.erb
|
211
279
|
- app/views/dokno/categories/new.html.erb
|
212
280
|
- app/views/layouts/dokno/application.html.erb
|
281
|
+
- app/views/partials/_category_header.html.erb
|
213
282
|
- app/views/partials/_form_errors.html.erb
|
214
283
|
- app/views/partials/_logs.html.erb
|
215
284
|
- app/views/partials/_pagination.html.erb
|