dokno 1.1.1 → 1.2.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/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
|