nestfans.com-wiki 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +34 -0
- data/Rakefile +37 -0
- data/app/assets/config/homeland_press_manifest.js +3 -0
- data/app/assets/javascripts/homeland/wiki/application.coffee +40 -0
- data/app/assets/stylesheets/homeland/wiki/application.scss +36 -0
- data/app/controllers/homeland/wiki/admin/page_versions_controller.rb +23 -0
- data/app/controllers/homeland/wiki/admin/pages_controller.rb +42 -0
- data/app/controllers/homeland/wiki/application_controller.rb +9 -0
- data/app/controllers/homeland/wiki/pages_controller.rb +92 -0
- data/app/helpers/homeland/wiki/application_helper.rb +10 -0
- data/app/models/homeland/wiki/ability.rb +32 -0
- data/app/models/page.rb +74 -0
- data/app/models/page_version.rb +7 -0
- data/app/views/homeland/wiki/admin/page_versions/index.html.erb +32 -0
- data/app/views/homeland/wiki/admin/page_versions/show.html.erb +20 -0
- data/app/views/homeland/wiki/admin/pages/_form.html.erb +29 -0
- data/app/views/homeland/wiki/admin/pages/edit.html.erb +6 -0
- data/app/views/homeland/wiki/admin/pages/index.html.erb +31 -0
- data/app/views/homeland/wiki/pages/_form.html.erb +41 -0
- data/app/views/homeland/wiki/pages/_sidebar.html.erb +14 -0
- data/app/views/homeland/wiki/pages/comments.html.erb +17 -0
- data/app/views/homeland/wiki/pages/edit.html.erb +8 -0
- data/app/views/homeland/wiki/pages/index.html.erb +13 -0
- data/app/views/homeland/wiki/pages/new.html.erb +8 -0
- data/app/views/homeland/wiki/pages/recent.html.erb +18 -0
- data/app/views/homeland/wiki/pages/show.html.erb +46 -0
- data/app/views/layouts/homeland/wiki/application.html.erb +15 -0
- data/config/locales/pages.en.yml +9 -0
- data/config/locales/pages.zh-CN.yml +9 -0
- data/config/locales/pages.zh-TW.yml +9 -0
- data/config/routes.rb +21 -0
- data/db/migrate/20170305220755_create_pages.rb +26 -0
- data/lib/homeland/wiki.rb +7 -0
- data/lib/homeland/wiki/engine.rb +30 -0
- data/lib/homeland/wiki/version.rb +7 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cc3675e1a95cc24be9a2200d4c976f41d0cded9f
|
4
|
+
data.tar.gz: 74cacac2c87a9187def1acd53d4289cf34f616a4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3fd2355979e7859c27badbb38ee6827ca87f698955e686a6d8b9b1cdbbef771b350e9d81a34da9f38026a70eaf4a9b1a91be29437230a23bd60bd892538f2487
|
7
|
+
data.tar.gz: 7b9ee126542ddef2ac85746fe4e29fb646957be913d6b22756183ec964b726dccdf468be64b4e6c63477cce5e1996f99038ce993ba087732e2af3f164c5a2572
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Homeland::Wiki
|
2
|
+
--------------
|
3
|
+
|
4
|
+
Wiki 栏目插件 for [Homeland](https://gethomeland.com)
|
5
|
+
|
6
|
+
简单的实现 /wiki 栏目,并在导航栏显示。
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
在 Homeland 应用的 Gemfile 增加:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'homeland-wiki'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
```bash
|
20
|
+
$ bundle
|
21
|
+
```
|
22
|
+
|
23
|
+
## Configuration
|
24
|
+
|
25
|
+
修改 Homeland 的 `modules` 配置,增加 `wiki` 以启用。
|
26
|
+
|
27
|
+
```yml
|
28
|
+
defaults: &defaults
|
29
|
+
# add "press" to modules
|
30
|
+
modules: 'topic,...,wiki'
|
31
|
+
```
|
32
|
+
|
33
|
+
## License
|
34
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Homeland::Wiki'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
load 'rails/tasks/statistics.rake'
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
require 'bundler/gem_tasks'
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.pattern = 'test/**/*_test.rb'
|
32
|
+
t.verbose = false
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Place all the behaviors and hooks related to the matching controller here.
|
2
|
+
# All this logic will automatically be available in application.js.
|
3
|
+
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
|
4
|
+
#
|
5
|
+
window.WikiView = Backbone.View.extend
|
6
|
+
el: "body"
|
7
|
+
events:
|
8
|
+
"click .editor-toolbar .preview": "togglePreviewView"
|
9
|
+
|
10
|
+
initialize: (opts) ->
|
11
|
+
@parentView = window._appView
|
12
|
+
$("<div id='preview' class='markdown form-control'></div>").insertAfter($("#page_body"))
|
13
|
+
$("#preview").hide()
|
14
|
+
window._editor = new Editor()
|
15
|
+
|
16
|
+
togglePreviewView: (e) ->
|
17
|
+
textarea = $("#page_body")
|
18
|
+
preview_box = $("#preview")
|
19
|
+
|
20
|
+
if $(e.target).hasClass("active")
|
21
|
+
$(e.target).removeClass("active")
|
22
|
+
preview_box.hide()
|
23
|
+
textarea.show()
|
24
|
+
else
|
25
|
+
$(e.target).addClass("active")
|
26
|
+
preview_box.show()
|
27
|
+
preview_box.css("height", textarea.height())
|
28
|
+
textarea.hide()
|
29
|
+
this.preview(preview_box, textarea.val())
|
30
|
+
return false
|
31
|
+
|
32
|
+
preview: (preview_box, val) ->
|
33
|
+
$.post '/wiki/preview', { body: val }, (data)->
|
34
|
+
preview_box.html(data)
|
35
|
+
false
|
36
|
+
false
|
37
|
+
|
38
|
+
document.addEventListener 'turbolinks:load', ->
|
39
|
+
if $('body').data('controller-name') in ['pages']
|
40
|
+
window._wikiView = new WikiView()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/*
|
2
|
+
*= require_self
|
3
|
+
*/
|
4
|
+
.page-pages {
|
5
|
+
.sidebar {
|
6
|
+
strong { color: #999; }
|
7
|
+
ul {
|
8
|
+
padding: 10px 10px 10px 30px;
|
9
|
+
li { line-height: 180%; }
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
.page-detail {
|
14
|
+
.card-header {
|
15
|
+
padding: 15px;
|
16
|
+
h1 { font-size: 20px; color: #111; margin: 0; margin-bottom: 6px;}
|
17
|
+
}
|
18
|
+
|
19
|
+
.info {
|
20
|
+
text-align:right;
|
21
|
+
padding:10px;
|
22
|
+
border-bottom:1px solid #eaeaea;
|
23
|
+
margin:-10px -10px 0;
|
24
|
+
background: #f5f5f5;
|
25
|
+
border-radius: 3px 3px 0 0;
|
26
|
+
margin-bottom:20px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.editors {
|
30
|
+
h3 { font-size:14px; color:#999;}
|
31
|
+
.media-object { display: inline; }
|
32
|
+
.buttons { margin-top: 10px; }
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Homeland::Wiki::Admin
|
2
|
+
class PageVersionsController < ::Admin::ApplicationController
|
3
|
+
def index
|
4
|
+
@page = Page.find(params[:page_id])
|
5
|
+
@page_versions = @page.versions.order(version: :desc).page(params[:page])
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
@page = Page.find(params[:page_id])
|
10
|
+
@page_version = @page.versions.find(params[:id])
|
11
|
+
end
|
12
|
+
|
13
|
+
def revert
|
14
|
+
@page = Page.find(params[:page_id])
|
15
|
+
@page_version = @page.versions.find(params[:id])
|
16
|
+
if @page.revert_version(@page_version.version)
|
17
|
+
redirect_to admin_page_versions_path(params[:page_id]), notice: "Wiki 内容已经撤销到了版本 #{@page_version.version}"
|
18
|
+
else
|
19
|
+
redirect_to admin_page_versions_path(params[:page_id]), alert: "版本撤销失败,原因: #{@page.errors.full_messages.join('<br />')}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Homeland::Wiki::Admin
|
2
|
+
class PagesController < ::Admin::ApplicationController
|
3
|
+
before_action :set_page, only: [:show, :edit, :update, :destroy]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@pages = Page.unscoped.order(id: :desc).page(params[:page])
|
7
|
+
end
|
8
|
+
|
9
|
+
def edit
|
10
|
+
end
|
11
|
+
|
12
|
+
def update
|
13
|
+
@page.title = params[:page][:title]
|
14
|
+
@page.body = params[:page][:body]
|
15
|
+
@page.slug = params[:page][:slug]
|
16
|
+
@page.locked = params[:page][:locked]
|
17
|
+
@page.user_id = current_user.id
|
18
|
+
|
19
|
+
if @page.save
|
20
|
+
redirect_to(admin_pages_path, notice: 'Page was successfully updated.')
|
21
|
+
else
|
22
|
+
render action: 'edit'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy
|
27
|
+
if @page.deleted_at.present?
|
28
|
+
@page.delete
|
29
|
+
else
|
30
|
+
@page.destroy
|
31
|
+
end
|
32
|
+
|
33
|
+
redirect_to(admin_pages_path)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def set_page
|
39
|
+
@page = Page.unscoped.find_by_slug(params[:id])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Homeland::Wiki
|
2
|
+
class PagesController < Homeland::Wiki::ApplicationController
|
3
|
+
require_module_enabled! :wiki
|
4
|
+
before_action :set_page, only: [:show, :edit, :update, :destroy, :comments]
|
5
|
+
|
6
|
+
etag { Setting.wiki_sidebar_html }
|
7
|
+
|
8
|
+
def index
|
9
|
+
fresh_when(Setting.wiki_index_html)
|
10
|
+
end
|
11
|
+
|
12
|
+
def recent
|
13
|
+
@pages = Page.recent.page(params[:page])
|
14
|
+
fresh_when(@pages)
|
15
|
+
end
|
16
|
+
|
17
|
+
def show
|
18
|
+
if @page.blank?
|
19
|
+
if current_user.blank?
|
20
|
+
render_404
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
redirect_to new_page_path(title: params[:id]), notice: 'Page not Found, Please create a new page'
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
@page.hits.incr(1)
|
29
|
+
fresh_when(@page)
|
30
|
+
end
|
31
|
+
|
32
|
+
def comments
|
33
|
+
render_404 if @page.blank?
|
34
|
+
end
|
35
|
+
|
36
|
+
def new
|
37
|
+
authorize! :create, Page
|
38
|
+
|
39
|
+
@page = Page.new
|
40
|
+
@page.slug = params[:title]
|
41
|
+
respond_to do |format|
|
42
|
+
format.html # new.html.erb
|
43
|
+
format.json { render json: @page }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def edit
|
48
|
+
authorize! :edit, @page
|
49
|
+
end
|
50
|
+
|
51
|
+
def create
|
52
|
+
authorize! :create, Page
|
53
|
+
|
54
|
+
@page = Page.new(page_params)
|
55
|
+
@page.user_id = current_user.id
|
56
|
+
@page.version_enable = true
|
57
|
+
|
58
|
+
if @page.save
|
59
|
+
redirect_to page_path(@page.slug), notice: t('common.create_success')
|
60
|
+
else
|
61
|
+
render action: 'new'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def update
|
66
|
+
authorize! :update, @page
|
67
|
+
|
68
|
+
@page.version_enable = true
|
69
|
+
@page.user_id = current_user.id
|
70
|
+
|
71
|
+
if @page.update(page_params)
|
72
|
+
redirect_to page_path(@page.slug), notice: t('common.update_success')
|
73
|
+
else
|
74
|
+
render action: 'edit'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def preview
|
79
|
+
render plain: Homeland::Markdown.call(params[:body])
|
80
|
+
end
|
81
|
+
|
82
|
+
protected
|
83
|
+
|
84
|
+
def set_page
|
85
|
+
@page = Page.find_by_slug(params[:id])
|
86
|
+
end
|
87
|
+
|
88
|
+
def page_params
|
89
|
+
params.require(:page).permit(:title, :body, :slug, :change_desc)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Homeland::Wiki
|
2
|
+
class Ability
|
3
|
+
include CanCan::Ability
|
4
|
+
|
5
|
+
attr_reader :user
|
6
|
+
|
7
|
+
def initialize(u)
|
8
|
+
@user = u
|
9
|
+
if @user.blank?
|
10
|
+
roles_for_anonymous
|
11
|
+
elsif @user.roles?(:admin)
|
12
|
+
can :manage, Page
|
13
|
+
elsif @user.roles?(:wiki_editor)
|
14
|
+
roles_for_wiki_editor
|
15
|
+
else
|
16
|
+
roles_for_anonymous
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def roles_for_wiki_editor
|
23
|
+
can :create, Page
|
24
|
+
can :update, Page, locked: false
|
25
|
+
end
|
26
|
+
|
27
|
+
def roles_for_anonymous
|
28
|
+
can [:read, :recent, :preview, :comments], Page
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
data/app/models/page.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
class Page < ApplicationRecord
|
2
|
+
include MarkdownBody
|
3
|
+
include Searchable
|
4
|
+
|
5
|
+
counter :hits, default: 0
|
6
|
+
|
7
|
+
second_level_cache expires_in: 2.weeks
|
8
|
+
|
9
|
+
has_many :versions, class_name: 'PageVersion'
|
10
|
+
|
11
|
+
attr_accessor :user_id, :change_desc, :version_enable
|
12
|
+
|
13
|
+
validates :slug, :title, :body, presence: true
|
14
|
+
# 当需要记录版本时,如果是更新,那么要求填写 :change_desc
|
15
|
+
validates :user_id, if: proc { |p| p.version_enable == true }, presence: true
|
16
|
+
validates :change_desc, if: proc { |p| p.version_enable == true && !p.new_record? }, presence: true
|
17
|
+
validates :slug, format: /\A[a-z0-9\-_]+\z/
|
18
|
+
validates :slug, uniqueness: true
|
19
|
+
|
20
|
+
before_save :append_editor
|
21
|
+
def append_editor
|
22
|
+
unless editor_ids.include?(user_id.to_i)
|
23
|
+
editor_ids << user_id.to_i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# 记录更新版本
|
28
|
+
after_save :create_version
|
29
|
+
def create_version
|
30
|
+
# 只有当 version_enable 为 true 的时候才记录版本
|
31
|
+
# 以免后台,以及其他的一些 update 时被误调用
|
32
|
+
return true unless version_enable
|
33
|
+
# 只有 body, title, slug 更改了才更新版本
|
34
|
+
if self.body_changed? || self.title_changed? || self.slug_changed?
|
35
|
+
update_column(:version, self.version + 1)
|
36
|
+
PageVersion.create(user_id: user_id,
|
37
|
+
page_id: id,
|
38
|
+
desc: change_desc || '',
|
39
|
+
version: version,
|
40
|
+
body: body,
|
41
|
+
title: title,
|
42
|
+
slug: slug)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def as_indexed_json(_options = {})
|
47
|
+
as_json(only: [:slug, :title, :body])
|
48
|
+
end
|
49
|
+
|
50
|
+
def indexed_changed?
|
51
|
+
slug_changed? || title_changed? || body_changed?
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_param
|
55
|
+
slug
|
56
|
+
end
|
57
|
+
|
58
|
+
# 撤掉到指定版本
|
59
|
+
def revert_version(version)
|
60
|
+
page_version = PageVersion.where(page_id: id, version: version).first
|
61
|
+
return false if page_version.blank?
|
62
|
+
update(body: page_version.body,
|
63
|
+
title: page_version.title,
|
64
|
+
slug: page_version.slug)
|
65
|
+
end
|
66
|
+
|
67
|
+
def editors
|
68
|
+
User.where(id: editor_ids)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.find_by_slug(slug)
|
72
|
+
fetch_by_uniq_keys(slug: slug)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<% content_for :sitemap do %>
|
2
|
+
<a href="<%= admin_pages_path %>">Wiki</a> <i class="fa fa-angle-right"></i>
|
3
|
+
<a href="<%= admin_page_path(params[:page_id]) %>">Page:<%= params[:page_id] %></a> <i class="fa fa-angle-right"></i>
|
4
|
+
<span class="current">版本历史</span>
|
5
|
+
<% end %>
|
6
|
+
<h1>Wiki 列表</h1>
|
7
|
+
|
8
|
+
<table class="table table-bordered table-striped table-condensed">
|
9
|
+
<tr class="head">
|
10
|
+
<td class="first">Version</td>
|
11
|
+
<td style="width:200px">Slug</td>
|
12
|
+
<td>Title</td>
|
13
|
+
<td>Desc</td>
|
14
|
+
<td>Creator</td>
|
15
|
+
<td>At</td>
|
16
|
+
<td></td>
|
17
|
+
</tr>
|
18
|
+
|
19
|
+
<% @page_versions.each do |item| %>
|
20
|
+
<tr>
|
21
|
+
<td class="first"><%= item.version %></td>
|
22
|
+
<td><%= item.slug %></td>
|
23
|
+
<td><%= item.title %></td>
|
24
|
+
<td><%= item.desc %></td>
|
25
|
+
<td><%= user_name_tag(item.user) %></td>
|
26
|
+
<td><%= l item.created_at, format: :long %></td>
|
27
|
+
<td><%= link_to 'View', admin_page_version_path(item.page_id, item.id) %>
|
28
|
+
<%= link_to 'Revert', revert_admin_page_version_path(item.page_id, item.id), 'data-confirm' => 'Are you sure?', method: :post %></td>
|
29
|
+
</tr>
|
30
|
+
<% end %>
|
31
|
+
</table>
|
32
|
+
<%= paginate @page_versions %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<% content_for :sitemap do %>
|
2
|
+
<a href="<%= admin_pages_path %>">Wiki</a> <i class="fa fa-angle-right"></i>
|
3
|
+
<a href="<%= edit_admin_page_path(params[:page_id]) %>">Page:<%= params[:page_id] %></a> <i class="fa fa-angle-right"></i>
|
4
|
+
<a href="<%= admin_page_versions_path(params[:page_id]) %>">版本历史</a> <i class="fa fa-angle-right"></i>
|
5
|
+
<span class="current">明细</span>
|
6
|
+
<% end %>
|
7
|
+
<div class="pull-right">
|
8
|
+
<%= link_to 'Revert', revert_admin_page_version_path(@page_version.page_id, @page_version.id), 'data-confirm' => 'Are you sure?', method: :post, class: "btn btn-danger" %>
|
9
|
+
</div>
|
10
|
+
<div class="field">
|
11
|
+
<%= user_name_tag @page_version.user %> 修改与 <%= l @page_version.created_at, format: :long %>
|
12
|
+
</div>
|
13
|
+
<div class="field">
|
14
|
+
Slug: <%= @page_version.slug %>
|
15
|
+
</div>
|
16
|
+
<div class="field">
|
17
|
+
Title: <%= @page_version.title %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<%= @page_version.body_html %>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<%= form_for [:admin, @page] do |f| %>
|
2
|
+
<%= render "shared/error_messages", target: @page %>
|
3
|
+
|
4
|
+
<div class="form-group form-check">
|
5
|
+
<%= f.check_box :locked, class: "form-check-input" %>
|
6
|
+
<%= f.label :locked, class: "form-check-label" %>
|
7
|
+
<div class="form-text">锁定后,前台非管理员将无法修改。</div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<div class="form-group">
|
11
|
+
<%= f.label :slug %>
|
12
|
+
<%= f.text_field :slug, class: "form-control" %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<div class="form-group">
|
16
|
+
<%= f.label :title %>
|
17
|
+
<%= f.text_field :title, class: "form-control" %>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="form-group">
|
21
|
+
<%= f.label :body %>
|
22
|
+
<%= f.text_area :body, class: "form-control", rows: 30 %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="form-actions">
|
26
|
+
<%= f.submit t("common.save"), class: "btn btn-primary", 'data-disable-with' => t("common.saving") %>
|
27
|
+
<%= link_to "取消", admin_pages_path, class: "btn btn-outline-primary" %>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% content_for :sitemap do %>
|
2
|
+
<span class="current">Wiki</span>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<table class="table table-bordered table-striped table-condensed">
|
6
|
+
<tr class="head">
|
7
|
+
<td class="first">ID</td>
|
8
|
+
<td style="width:200px">Slug</td>
|
9
|
+
<td>Title</td>
|
10
|
+
<td>at</td>
|
11
|
+
<td>lock</td>
|
12
|
+
<td>Version</td>
|
13
|
+
<td style="width:80px;"></td>
|
14
|
+
</tr>
|
15
|
+
|
16
|
+
<% @pages.each do |page| %>
|
17
|
+
<tr class="<%= 'deleted' if !page.deleted_at.blank? %>">
|
18
|
+
<td class="first"><%= page.id %></td>
|
19
|
+
<td><%= page.slug %></td>
|
20
|
+
<td><%= truncate(page.title, length: 30) %></td>
|
21
|
+
<td><%= l page.created_at, format: :short %></td>
|
22
|
+
<td><%= page.locked %></td>
|
23
|
+
<td><%= page.version %></td>
|
24
|
+
<td>
|
25
|
+
<%= link_to '', admin_page_versions_path(page.id), class: "fa fa-clock-o", title: "修改记录" %>
|
26
|
+
<%= link_to '', edit_admin_page_path(page), class: "fa fa-pencil" %>
|
27
|
+
<%= link_to '', admin_page_path(page), 'data-confirm' => 'Are you sure?', method: :delete, class: "fa fa-trash" %></td>
|
28
|
+
</tr>
|
29
|
+
<% end %>
|
30
|
+
</table>
|
31
|
+
<%= paginate @pages %>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<%= form_for @page do |f| %>
|
2
|
+
<%= render "shared/error_messages", target: @page %>
|
3
|
+
|
4
|
+
<div class="form-group">
|
5
|
+
<%= f.label :slug %>
|
6
|
+
<%= f.text_field :slug, class: "form-control" %>
|
7
|
+
<div class="form-text">
|
8
|
+
<%= Setting.base_url %>/wiki/:slug
|
9
|
+
</div>
|
10
|
+
</div>
|
11
|
+
|
12
|
+
<div class="form-group">
|
13
|
+
<%= f.label :title %>
|
14
|
+
<%= f.text_field :title, class: "form-control" %>
|
15
|
+
</div>
|
16
|
+
|
17
|
+
<div class="edit-tools">
|
18
|
+
<%= render "/shared/editor_toolbar" %>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<div class="form-group">
|
22
|
+
<%= f.text_area :body, rows: 30, class: "form-control topic-editor" %>
|
23
|
+
|
24
|
+
<div class="form-text">
|
25
|
+
请使用 Markdown 格式编写,可以试试用 <a href="https://www.typora.io" target="_blank">Typora</a> 这个 App 来编写。
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<% if !@page.new_record? %>
|
30
|
+
<div class="form-group">
|
31
|
+
<%= f.label :change_desc %>
|
32
|
+
<%= f.text_area :change_desc, class: "form-control", rows: 2 %>
|
33
|
+
<div class="form-text"><%= t("pages.describe_this_time_change") %></div>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<div class="form-actions">
|
38
|
+
<%= f.submit t("common.save"), class: "btn btn-primary", 'data-disable-with' => t("common.saving") %>
|
39
|
+
<%= link_to t("common.cancel"), pages_path, class: "btn btn-outline-primary" %>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<div class="sidebar wiki-sidebar col-sm-3 <%= "hide-ios" if action_name != "index" %>">
|
2
|
+
<div class="card">
|
3
|
+
<div class="card-body">
|
4
|
+
<strong>导航</strong>
|
5
|
+
<ul>
|
6
|
+
<li><a href="/wiki">首页</a></li>
|
7
|
+
<li><%= link_to(t("pages.wiki_index"), recent_pages_path) %></li>
|
8
|
+
<li class="hide-ios"><%= link_to(t("pages.new_page"), new_page_path)%></li>
|
9
|
+
</ul>
|
10
|
+
|
11
|
+
<%= raw Setting.wiki_sidebar_html %>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% title_tag [t('pages.comments'), @page.title].join(' · ') %>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<%= render 'sidebar' %>
|
5
|
+
|
6
|
+
<div class="col-md-9">
|
7
|
+
<div class="card">
|
8
|
+
<div id="comments" class="card-body">
|
9
|
+
《<%= link_to @page.title, page_path(@page.slug) %>》 - <%= t('pages.comments') %>
|
10
|
+
</div>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<div class="hide-ios">
|
14
|
+
<%= render "/shared/comments", commentable: @page %>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<% title_tag t('pages.wiki_index') %>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<%= render "sidebar" %>
|
5
|
+
|
6
|
+
<div class="col-md-9">
|
7
|
+
<div class="card">
|
8
|
+
<div class="card-header hide-ios"><%= t("pages.wiki_index") %></div>
|
9
|
+
<div class="card-body">
|
10
|
+
<ul>
|
11
|
+
<% @pages.each do |item| %>
|
12
|
+
<li><%= page_title_tag(item) %></li>
|
13
|
+
<% end %>
|
14
|
+
</ul>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</div>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<% title_tag @page.title %>
|
2
|
+
|
3
|
+
<div class="row">
|
4
|
+
<%= render 'sidebar' %>
|
5
|
+
|
6
|
+
<div class="col-md-9 page-detail">
|
7
|
+
<div class="card">
|
8
|
+
<% if !@page.locked or admin? %>
|
9
|
+
<div class="card-header">
|
10
|
+
<h1><%= @page.title %></h1>
|
11
|
+
<div class="infos">
|
12
|
+
<%= link_to comments_page_path(@page.slug) do %>
|
13
|
+
<%= @page.comments_count %> 条评论
|
14
|
+
<% end %>,
|
15
|
+
<%= @page.version %> 次修正,<%= @page.hits %> 次阅读, <%= t("common.last_modified_at")%> <%= timeago(@page.updated_at) %>
|
16
|
+
<span class="pull-right opts hide-ios">
|
17
|
+
<%= link_to(icon_tag('pencil'), edit_page_path(@page)) if can? :edit, @page %>
|
18
|
+
</span>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
<div class="card-body markdown markdown-toc">
|
25
|
+
<article>
|
26
|
+
<%= @page.body_html %>
|
27
|
+
</article>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="card-footer editors clearfix">
|
31
|
+
<div class="heading">
|
32
|
+
<%= t("pages.wiki_page_contributors")%>
|
33
|
+
<span class="pull-right"><%= social_share_button_tag h("#{@page.title} via: @#{Setting.twitter_id} ") %></span>
|
34
|
+
</div>
|
35
|
+
<div class="avatars">
|
36
|
+
<% @page.editors.each do |item| %>
|
37
|
+
<%= user_avatar_tag(item, :xs) %>
|
38
|
+
<% end %>
|
39
|
+
</div>
|
40
|
+
<div class="buttons hide-ios">
|
41
|
+
<%= link_to "发表评论", comments_page_path(@page.slug, anchor: "new_comment"), class: "btn btn-success" %>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% content_for :stylesheets do %>
|
2
|
+
<%= stylesheet_link_tag "homeland/wiki/application", media: "all" %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<% content_for :javascripts do %>
|
6
|
+
<%= javascript_include_tag "homeland/wiki/application" %>
|
7
|
+
<% end %>
|
8
|
+
|
9
|
+
<% content_for :main do %>
|
10
|
+
<div id="homeland-wiki">
|
11
|
+
<%= yield %>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<%= render template: "/layouts/application" %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
"en":
|
2
|
+
pages:
|
3
|
+
describe_this_time_change: "Please describe the purpose of this modification."
|
4
|
+
edit_page: "Edit Page"
|
5
|
+
new_page: "New Page"
|
6
|
+
wiki_index: "Wiki Index"
|
7
|
+
wiki_page_contributors: "Contributors:"
|
8
|
+
wiki_page_lock_warning: "This page is locked and only Adminstrators are authorised to modify."
|
9
|
+
comments: 'Comments'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Homeland::Wiki::Engine.routes.draw do
|
2
|
+
resources :pages, path: 'wiki' do
|
3
|
+
collection do
|
4
|
+
get :recent
|
5
|
+
post :preview
|
6
|
+
end
|
7
|
+
member do
|
8
|
+
get :comments
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :admin do
|
13
|
+
resources :pages, path: 'wiki' do
|
14
|
+
resources :versions, controller: :page_versions do
|
15
|
+
member do
|
16
|
+
post :revert
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class CreatePages < ActiveRecord::Migration[5.0]
|
2
|
+
def up
|
3
|
+
return if ActiveRecord::Base.connection.table_exists? :pages
|
4
|
+
|
5
|
+
create_table :pages do |t|
|
6
|
+
t.string :slug, null: false
|
7
|
+
t.string :title, null: false
|
8
|
+
t.text :body, null: false
|
9
|
+
t.boolean :locked, default: false
|
10
|
+
t.integer :version, default: 0, null: false
|
11
|
+
t.integer :editor_ids, default: [], null: false, array: true
|
12
|
+
t.integer :word_count, default: 0, null: false
|
13
|
+
t.integer :changes_cout, default: 1, null: false
|
14
|
+
t.integer :comments_count, default: 0, null: false
|
15
|
+
t.datetime :deleted_at
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :pages, :slug, unique: true
|
21
|
+
end
|
22
|
+
|
23
|
+
def down
|
24
|
+
drop_table :pages, if_exists: true
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Homeland
|
2
|
+
module Wiki
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
isolate_namespace Homeland::Wiki
|
5
|
+
|
6
|
+
initializer 'homeland.wiki.init' do |app|
|
7
|
+
if Setting.has_module?(:wiki)
|
8
|
+
Homeland.register_plugin do |plugin|
|
9
|
+
plugin.name = 'wiki'
|
10
|
+
plugin.display_name = '知识库'
|
11
|
+
plugin.description = Homeland::Wiki::DESCRIPTION
|
12
|
+
plugin.version = Homeland::Wiki::VERSION
|
13
|
+
plugin.navbar_link = true
|
14
|
+
plugin.user_menu_link = false
|
15
|
+
plugin.root_path = "/wiki"
|
16
|
+
plugin.admin_path = "/admin/wiki"
|
17
|
+
plugin.admin_navbar_link = true
|
18
|
+
plugin.spec_path = config.root.join('spec')
|
19
|
+
end
|
20
|
+
|
21
|
+
app.routes.prepend do
|
22
|
+
mount Homeland::Wiki::Engine, at: '/'
|
23
|
+
end
|
24
|
+
|
25
|
+
app.config.paths["db/migrate"].concat(config.paths["db/migrate"].expanded)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nestfans.com-wiki
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Griffin Qiu
|
8
|
+
- Jason Lee
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2019-07-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '5'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '5'
|
28
|
+
description: Display Wiki channel in navbar for wike pages.
|
29
|
+
email:
|
30
|
+
- griffinqiu@gmail.com
|
31
|
+
- huacnlee@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- app/assets/config/homeland_press_manifest.js
|
39
|
+
- app/assets/javascripts/homeland/wiki/application.coffee
|
40
|
+
- app/assets/stylesheets/homeland/wiki/application.scss
|
41
|
+
- app/controllers/homeland/wiki/admin/page_versions_controller.rb
|
42
|
+
- app/controllers/homeland/wiki/admin/pages_controller.rb
|
43
|
+
- app/controllers/homeland/wiki/application_controller.rb
|
44
|
+
- app/controllers/homeland/wiki/pages_controller.rb
|
45
|
+
- app/helpers/homeland/wiki/application_helper.rb
|
46
|
+
- app/models/homeland/wiki/ability.rb
|
47
|
+
- app/models/page.rb
|
48
|
+
- app/models/page_version.rb
|
49
|
+
- app/views/homeland/wiki/admin/page_versions/index.html.erb
|
50
|
+
- app/views/homeland/wiki/admin/page_versions/show.html.erb
|
51
|
+
- app/views/homeland/wiki/admin/pages/_form.html.erb
|
52
|
+
- app/views/homeland/wiki/admin/pages/edit.html.erb
|
53
|
+
- app/views/homeland/wiki/admin/pages/index.html.erb
|
54
|
+
- app/views/homeland/wiki/pages/_form.html.erb
|
55
|
+
- app/views/homeland/wiki/pages/_sidebar.html.erb
|
56
|
+
- app/views/homeland/wiki/pages/comments.html.erb
|
57
|
+
- app/views/homeland/wiki/pages/edit.html.erb
|
58
|
+
- app/views/homeland/wiki/pages/index.html.erb
|
59
|
+
- app/views/homeland/wiki/pages/new.html.erb
|
60
|
+
- app/views/homeland/wiki/pages/recent.html.erb
|
61
|
+
- app/views/homeland/wiki/pages/show.html.erb
|
62
|
+
- app/views/layouts/homeland/wiki/application.html.erb
|
63
|
+
- config/locales/pages.en.yml
|
64
|
+
- config/locales/pages.zh-CN.yml
|
65
|
+
- config/locales/pages.zh-TW.yml
|
66
|
+
- config/routes.rb
|
67
|
+
- db/migrate/20170305220755_create_pages.rb
|
68
|
+
- lib/homeland/wiki.rb
|
69
|
+
- lib/homeland/wiki/engine.rb
|
70
|
+
- lib/homeland/wiki/version.rb
|
71
|
+
homepage: https://github.com/ruby-china/homeland-wiki
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.6.14
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Display Wiki channel in navbar for wike pages.
|
95
|
+
test_files: []
|