sqliki 0.0.3
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.
- data/USAGE +30 -0
- data/sqliki_generator-0.0.3.gemspec +39 -0
- data/sqliki_generator.rb +32 -0
- data/templates/README +95 -0
- data/templates/controller_sqliki_controller.rb +76 -0
- data/templates/lib_sanitize_html.rb +143 -0
- data/templates/model_draft.rb +141 -0
- data/templates/model_link.rb +2 -0
- data/templates/model_page.rb +31 -0
- data/templates/view__form.rhtml +12 -0
- data/templates/view_create.rhtml +8 -0
- data/templates/view_edit.rhtml +9 -0
- data/templates/view_inplace_edit.rhtml +2 -0
- data/templates/view_list.rhtml +23 -0
- data/templates/view_rollback.rhtml +2 -0
- data/templates/view_show.rhtml +18 -0
- metadata +72 -0
data/USAGE
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
NAME
|
2
|
+
sqliki - creates a SQL-based wiki within a rails application
|
3
|
+
|
4
|
+
SYNOPSIS
|
5
|
+
sqliki [Controller name]
|
6
|
+
|
7
|
+
Good names are Sqliki, Wiki, Chalkboard, Elmo, ...
|
8
|
+
|
9
|
+
DESCRIPTION
|
10
|
+
This generator creates a rudimentary SQL-based wiki.
|
11
|
+
|
12
|
+
EXAMPLE
|
13
|
+
./script/generate sqliki Wiki
|
14
|
+
|
15
|
+
This will generate a Wiki controller which provides users:
|
16
|
+
/wiki/index (==list) -- list all pages (alphabeticaly)
|
17
|
+
/wiki/wanted -- ..pages with no content
|
18
|
+
/wiki/orphaned -- ..pages that aren't linked to
|
19
|
+
/wiki/recently_revised -- ..pages in reverse order of edits
|
20
|
+
/wiki/show/(page) -- Show an existing page
|
21
|
+
/wiki/create/(page) -- Create a new page
|
22
|
+
/wiki/edit/(page) -- Edit an existing page
|
23
|
+
...and additional methods for control flow / internal use:
|
24
|
+
/wiki/raw
|
25
|
+
/wiki/html
|
26
|
+
/wiki/inplace_edit
|
27
|
+
/wiki/destroy
|
28
|
+
/wiki/rollback/(draft)
|
29
|
+
|
30
|
+
The tables are always called pages, drafts, and links
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
SPEC = Gem::Specification.new do |s|
|
4
|
+
s.name = %q{sqliki}
|
5
|
+
s.version = "0.0.3"
|
6
|
+
s.date = %q{2005-08-25}
|
7
|
+
s.summary = %q{[Rails] SQL-based wiki generator.}
|
8
|
+
s.require_paths = ["."]
|
9
|
+
s.email = %q{Markus@reality.com}
|
10
|
+
s.homepage = %q{http://www.rubyonrails.org/show/Generators}
|
11
|
+
s.description = %q{Generates code for (primative) a SQL-based wiki within your Rails app.}
|
12
|
+
s.authors = ["Markus J. Q. Roberts"]
|
13
|
+
s.files = %w{
|
14
|
+
USAGE
|
15
|
+
templates/lib_sanitize_html.rb
|
16
|
+
templates/README
|
17
|
+
templates/model_draft.rb
|
18
|
+
templates/view_edit.rhtml
|
19
|
+
templates/view__form.rhtml
|
20
|
+
templates/view_inplace_edit.rhtml
|
21
|
+
templates/view_list.rhtml
|
22
|
+
templates/view_create.rhtml
|
23
|
+
templates/view_rollback.rhtml
|
24
|
+
templates/view_show.rhtml
|
25
|
+
templates/model_link.rb
|
26
|
+
templates/model_page.rb
|
27
|
+
templates/controller_sqliki_controller.rb
|
28
|
+
sqliki_generator.rb
|
29
|
+
sqliki_generator-0.0.3.gemspec
|
30
|
+
}
|
31
|
+
s.add_dependency('rails', [">= 0.13.1"])
|
32
|
+
s.add_dependency('RedCloth')
|
33
|
+
end
|
34
|
+
|
35
|
+
if $0 == __FILE__
|
36
|
+
Gem::manage_gems
|
37
|
+
Gem::Builder.new(SPEC).build
|
38
|
+
end
|
39
|
+
|
data/sqliki_generator.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
class SqlikiGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
|
5
|
+
# Models.
|
6
|
+
%w{page draft link}.each do |x|
|
7
|
+
m.template "model_#{x}.rb",File.join("app/models", class_path, "#{x}.rb")
|
8
|
+
end
|
9
|
+
|
10
|
+
# Views.
|
11
|
+
m.directory File.join("app/views", class_path, file_name)
|
12
|
+
%w{edit _form inplace_edit list create rollback show }.each do |x|
|
13
|
+
m.template "view_#{x}.rhtml",File.join("app/views", class_path, file_name, "#{x}.rhtml")
|
14
|
+
end
|
15
|
+
|
16
|
+
m.template "controller_sqliki_controller.rb",File.join("app/controllers", class_path, "#{file_name}_controller.rb")
|
17
|
+
|
18
|
+
# Libs.
|
19
|
+
%w{sanitize_html}.each do |x|
|
20
|
+
m.template "lib_#{x}.rb",File.join("lib", class_path, "#{x}.rb")
|
21
|
+
end
|
22
|
+
|
23
|
+
m.template "README", "README_SQLIKI"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :controller_class_name
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
|
data/templates/README
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
== Installation
|
2
|
+
|
3
|
+
NOTE: THIS IS THE VERY FIRST ALPHA VERSION OF SQLIKI!!!
|
4
|
+
|
5
|
+
Done generating SQLiki. but there are still a few things you have to
|
6
|
+
do manually.
|
7
|
+
|
8
|
+
* You will need a login system of some kind. I have been using the simple
|
9
|
+
login generator.
|
10
|
+
|
11
|
+
* SQLiki needs to know the current user; it looks for this in
|
12
|
+
User.current_user. If your login system provides this, fine. The simple
|
13
|
+
login generator does not, but you can add it reasonably easily. Just add
|
14
|
+
something like the following to your application.rb:
|
15
|
+
|
16
|
+
class << User
|
17
|
+
cattr_accessor :current_user unless self.respond_to? :current_user
|
18
|
+
end
|
19
|
+
|
20
|
+
class ApplicationController < ActionController::Base
|
21
|
+
before_filter :note_the_current_user
|
22
|
+
def note_the_current_user
|
23
|
+
User.current_user = @session[:user] if User.respond_to? :current_user=
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
* You will need Why T.L.S.'s RedCloth (which you probably already have)
|
29
|
+
|
30
|
+
* You will need three tables (pages, drafts, and links):
|
31
|
+
|
32
|
+
--
|
33
|
+
-- Table structure for table 'pages'
|
34
|
+
-- These are just the headers (page names); the text is in
|
35
|
+
-- the draft identified by "current_draft_id"
|
36
|
+
--
|
37
|
+
|
38
|
+
CREATE TABLE pages (
|
39
|
+
id int(10) unsigned NOT NULL auto_increment,
|
40
|
+
type varchar(80) NOT NULL default '',
|
41
|
+
created_on datetime default NULL,
|
42
|
+
updated_on datetime default NULL,
|
43
|
+
lock_version int(11) default '0',
|
44
|
+
current_draft_id int(11) NOT NULL default '0',
|
45
|
+
title varchar(80) NOT NULL default '',
|
46
|
+
created_by int(11) NOT NULL default '0',
|
47
|
+
PRIMARY KEY (id)
|
48
|
+
) TYPE=MyISAM;
|
49
|
+
|
50
|
+
--
|
51
|
+
-- Table structure for table 'drafts'
|
52
|
+
-- These are were the text is stored. Note that drafts make
|
53
|
+
-- a tree, since each derived-draft knows which draft it was
|
54
|
+
-- based on.
|
55
|
+
--
|
56
|
+
|
57
|
+
CREATE TABLE drafts (
|
58
|
+
id int(10) unsigned NOT NULL auto_increment,
|
59
|
+
type varchar(80) NOT NULL default '',
|
60
|
+
created_on datetime default NULL,
|
61
|
+
draft_of_page_id int(11) default '0',
|
62
|
+
based_on_draft_id int(11) default '0',
|
63
|
+
body text NOT NULL,
|
64
|
+
created_by int(11) NOT NULL default '0',
|
65
|
+
PRIMARY KEY (id)
|
66
|
+
) TYPE=MyISAM;
|
67
|
+
|
68
|
+
--
|
69
|
+
-- Table structure for table 'links'
|
70
|
+
-- These just keep track of which drafts refer to which pages;
|
71
|
+
-- that is, whenever a draft of one page contains a WikiWord that
|
72
|
+
-- generates a link to another page, that fact is noted here.
|
73
|
+
--
|
74
|
+
|
75
|
+
CREATE TABLE links (
|
76
|
+
draft_id int(11) NOT NULL default '0',
|
77
|
+
page_id int(11) NOT NULL default '0'
|
78
|
+
) TYPE=MyISAM;
|
79
|
+
|
80
|
+
|
81
|
+
== How to use it
|
82
|
+
|
83
|
+
== Tips & Tricks
|
84
|
+
|
85
|
+
== Changelog
|
86
|
+
|
87
|
+
0.0.1
|
88
|
+
First gem release
|
89
|
+
0.0.2
|
90
|
+
Made the name of the controller changeable
|
91
|
+
Removed the system specific path for RedCloth
|
92
|
+
Implemented Orphaned/Wanted/Recently_revised
|
93
|
+
Cleaned up the controller interface (w. the the
|
94
|
+
trick from Tobias Luetke's Postback Generator)
|
95
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
class <%= class_name %>Controller < ApplicationController
|
2
|
+
model :draft
|
3
|
+
include LoginSystem
|
4
|
+
before_filter :login_required
|
5
|
+
def identify_page
|
6
|
+
@page ||= Page.find_by_title(params[:id])
|
7
|
+
end
|
8
|
+
def index
|
9
|
+
list
|
10
|
+
render :action => 'list'
|
11
|
+
end
|
12
|
+
def raw
|
13
|
+
render_text identify_page.current_draft.raw
|
14
|
+
end
|
15
|
+
def html
|
16
|
+
render_text identify_page.current_draft.html
|
17
|
+
end
|
18
|
+
def rollback
|
19
|
+
identify_page
|
20
|
+
#@page.current_draft = ???
|
21
|
+
render :action => 'show'
|
22
|
+
end
|
23
|
+
def wanted
|
24
|
+
list :wanted
|
25
|
+
render :action => 'list'
|
26
|
+
end
|
27
|
+
def orphaned
|
28
|
+
list :orphaned
|
29
|
+
render :action => 'list'
|
30
|
+
end
|
31
|
+
def recently_revised
|
32
|
+
list :recently_revised
|
33
|
+
render :action => 'list'
|
34
|
+
end
|
35
|
+
def list(condition=:all)
|
36
|
+
@page_pages, @pages = paginate :page, {:per_page => 20}.merge(case condition
|
37
|
+
when :wanted then {:conditions => 'current_draft_id IS NULL'}
|
38
|
+
when :orphaned then {
|
39
|
+
:join => 'p LEFT JOIN links l ON l.page_id = p.id left join drafts dx on dx.id = l.draft_id left join pages px on px.current_draft_id = dx.id',
|
40
|
+
:conditions => 'page_id IS NULL'
|
41
|
+
}
|
42
|
+
when :recently_revised then {:order_by => 'updated_on DESC'}
|
43
|
+
else {:order_by => 'title'}
|
44
|
+
end)
|
45
|
+
end
|
46
|
+
def show
|
47
|
+
identify_page || redirect_to(:action => 'create', :id => @params[:id])
|
48
|
+
end
|
49
|
+
def create
|
50
|
+
@page = Page.new_page(@params[:id])
|
51
|
+
if @request.post? and @page.update_attributes(params[:page]) and @page.save
|
52
|
+
flash[:notice] = 'Page was successfully created.'
|
53
|
+
redirect_to :action => 'show', :id => @page.title
|
54
|
+
end
|
55
|
+
end
|
56
|
+
def inplace_edit
|
57
|
+
if not identify_page
|
58
|
+
redirect_to(:action => 'create', :id => @params[:id])
|
59
|
+
elsif @request.post? and @page.update_attributes(params[:page])
|
60
|
+
redirect_to :action => 'html', :id => @page.title
|
61
|
+
end
|
62
|
+
end
|
63
|
+
def edit
|
64
|
+
if not identify_page
|
65
|
+
redirect_to(:action => 'create', :id => @params[:id])
|
66
|
+
elsif @request.post? and @page.update_attributes(params[:page])
|
67
|
+
flash[:notice] = 'Page was successfully updated.'
|
68
|
+
redirect_to :action => 'show', :id => @page.title
|
69
|
+
end
|
70
|
+
end
|
71
|
+
def destroy
|
72
|
+
identify_page.destroy if @request.post?
|
73
|
+
redirect_to :action => 'list'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,143 @@
|
|
1
|
+
#
|
2
|
+
# Written from scratch to address specific problems I was having with instiki/RedCloth
|
3
|
+
#
|
4
|
+
# * Mismatched tags (especially DIVs) seriously messed up the page layout
|
5
|
+
# * View Changes made code blocks hard to read (lost line breaks)
|
6
|
+
# * Inserting/deleting block-level tags caused messed up page layout
|
7
|
+
#
|
8
|
+
# See An_html_janitor.initialze for a birds-eye view of the algorithm.
|
9
|
+
#
|
10
|
+
# (c) 2005 By Markus J. Q. Roberts
|
11
|
+
# Usage, modification, etc. of this program is permitted under the GPL, Ruby's License, Rail's
|
12
|
+
# License, or Instiki's License (your choice)
|
13
|
+
#
|
14
|
+
require 'ostruct'
|
15
|
+
require 'cgi'
|
16
|
+
|
17
|
+
class An_html_janitor < String
|
18
|
+
Tags_we_dont_expect_to_close = %w{ area br img input keygen li link meta p param td th thead tr }
|
19
|
+
Priority = Hash.new( 0 ).update({ 'ins' => 10, 'del' => 10 })
|
20
|
+
def initialize(raw_html)
|
21
|
+
replace raw_html
|
22
|
+
@safe_house = []
|
23
|
+
sequester!("previous protected zone",/@protected \w+ \d+@/)
|
24
|
+
sequester!("html comment", /<!--.*?-->/m )
|
25
|
+
#To do: sequester attributes that contain "<" and/or ">"
|
26
|
+
spiff_up('ins')
|
27
|
+
spiff_up('del')
|
28
|
+
ballance_tags
|
29
|
+
remove_empty_spans
|
30
|
+
unseal!("html comment","previous protected zone")
|
31
|
+
end
|
32
|
+
def stash(text)
|
33
|
+
@safe_house << [[],text.to_s,[]]
|
34
|
+
@safe_house.length - 1
|
35
|
+
end
|
36
|
+
def token_for(group,id)
|
37
|
+
"@protected #{group} #{id}@"
|
38
|
+
end
|
39
|
+
def sequester!(group,reg_exp)
|
40
|
+
gsub!(reg_exp) { |match| token_for(group,stash(match)) }
|
41
|
+
end
|
42
|
+
def unseal!(*groups)
|
43
|
+
gsub!(/@protected (?:#{groups.join('|')}) (\d+)@/) { |n| @safe_house[$1.to_i] }
|
44
|
+
end
|
45
|
+
def wrap(token,new_pre,new_post)
|
46
|
+
pre,core,post = @safe_house[token]
|
47
|
+
@safe_house[token].replace [pre+[new_pre],core,[new_post]+post]
|
48
|
+
end
|
49
|
+
def escape_core(token)
|
50
|
+
pre,core,post = @safe_house[token]
|
51
|
+
@safe_house[token].replace [[],CGI.escapeHTML(core),[]]
|
52
|
+
end
|
53
|
+
def spiff_up(tag)
|
54
|
+
gsub!(%r{<#{tag}(.*?)>(.*?)</#{tag}>}) {
|
55
|
+
"<#{tag}#{$1}>#{CGI.escapeHTML($2.gsub(%r{<(/?\w+).*?>}) {"<#{$1}>"})}</#{tag}>"
|
56
|
+
}
|
57
|
+
end
|
58
|
+
def ballance_tags
|
59
|
+
stack = []
|
60
|
+
gsub!(%r{<(.*?)>}) { |chunk| case $1
|
61
|
+
when %r{/$} #self-closing tag
|
62
|
+
chunk
|
63
|
+
when %r{^(\w+)} #opening tag
|
64
|
+
tag = $1.downcase
|
65
|
+
#print "opening #{tag} \n #{stack.collect {|q| q.desc}.inspect}\n #{@safe_house.inspect}#\n"
|
66
|
+
if Tags_we_dont_expect_to_close.include? tag
|
67
|
+
chunk
|
68
|
+
else
|
69
|
+
stack.push OpenStruct.new(
|
70
|
+
:tag => tag,
|
71
|
+
:priority => Priority[tag],
|
72
|
+
:text => chunk,
|
73
|
+
:start_tag => stash(chunk),
|
74
|
+
:expected_close => "</#{tag}>",
|
75
|
+
:desc => "#{chunk}...</#{tag}>"
|
76
|
+
)
|
77
|
+
token_for("start tag",stack.last.start_tag)
|
78
|
+
end
|
79
|
+
when %r{^/(\w+)} #closing tag
|
80
|
+
tag = $1.downcase
|
81
|
+
#print "closing #{tag}\n #{stack.collect {|q| q.tag}.inspect}\n #{@safe_house.inspect}\n"
|
82
|
+
if Tags_we_dont_expect_to_close.include? tag
|
83
|
+
mode = :ignore
|
84
|
+
else
|
85
|
+
pre = []
|
86
|
+
priority = Priority[tag]
|
87
|
+
outranked = false
|
88
|
+
while s = stack.pop and tag != s.tag
|
89
|
+
outranked ||= s.priority > priority
|
90
|
+
pre << s
|
91
|
+
end
|
92
|
+
mode = if !s or outranked
|
93
|
+
:escape_it
|
94
|
+
elsif tag != 'div'
|
95
|
+
:breaking_this_one
|
96
|
+
else
|
97
|
+
:breaking_others
|
98
|
+
end
|
99
|
+
stack.push *pre.reverse
|
100
|
+
end
|
101
|
+
case mode
|
102
|
+
when :breaking_this_one
|
103
|
+
pre.collect {|s| s.expected_close }.join + chunk + pre.reverse.collect {|s| s.text }.join
|
104
|
+
when :breaking_others
|
105
|
+
this_head = s.text
|
106
|
+
pre.each { |s| wrap(s.start_tag,chunk,this_head) }
|
107
|
+
chunk
|
108
|
+
when :ignore
|
109
|
+
''
|
110
|
+
else
|
111
|
+
escape_core(s.start_tag) if s
|
112
|
+
CGI.escapeHTML(chunk)
|
113
|
+
end
|
114
|
+
else
|
115
|
+
chunk
|
116
|
+
end }
|
117
|
+
replace self+stack.reverse.collect { |open_tag| open_tag.expected_close }.join
|
118
|
+
unseal!("start tag")
|
119
|
+
end
|
120
|
+
def remove_empty_spans
|
121
|
+
while gsub!(%r{<(\w+)[^>]*?></\1>},''); end
|
122
|
+
end
|
123
|
+
def remove_attributes(*attributes_to_remove)
|
124
|
+
return self if attributes_to_remove.length == 0
|
125
|
+
kill_pattern = /(#{attributes_to_remove.join('|')})(=(".*?"|\S*))?/i
|
126
|
+
gsub!(%r{<(\w+) +(.*?)>}) { |match| "<#{$1} #{$2.gsub(kill_pattern,'')}>" }
|
127
|
+
self
|
128
|
+
end
|
129
|
+
def remove_styles(*styles_to_remove)
|
130
|
+
return self if styles_to_remove.length == 0
|
131
|
+
style_kill_pattern = /(#{styles_to_remove.join('|')}).*?(;|$)/i
|
132
|
+
gsub!(%r{<(\w+) +(.*?)>}i) { |match|
|
133
|
+
"<#{$1} #{$2.gsub!(%r{style="(.*?)"}) { |match| "style=""#{$1.gsub(style_kill_pattern,'')}""" }}>"
|
134
|
+
}
|
135
|
+
self
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def sanitize_html(raw_html)
|
140
|
+
An_html_janitor.new(raw_html)
|
141
|
+
end
|
142
|
+
|
143
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'sanitize_html'
|
2
|
+
require 'redcloth'
|
3
|
+
|
4
|
+
class Draft < ActiveRecord::Base
|
5
|
+
acts_as_tree :foreign_key => 'based_on_draft_id'
|
6
|
+
has_and_belongs_to_many :links,:class_name => 'Page',:join_table => 'links'
|
7
|
+
belongs_to :author, :class_name => 'User', :foreign_key => :created_by
|
8
|
+
belongs_to :page, :foreign_key => :draft_of_page_id
|
9
|
+
def before_create
|
10
|
+
html #this updates the cross reference (link) table
|
11
|
+
true
|
12
|
+
end
|
13
|
+
def raw
|
14
|
+
body
|
15
|
+
end
|
16
|
+
class RopaRojo < RedCloth
|
17
|
+
def hard_break(text)
|
18
|
+
@rules.each do |rule_name|
|
19
|
+
method( rule_name ).call( text ) if rule_name.to_s.match /^pre_/
|
20
|
+
end
|
21
|
+
super
|
22
|
+
end
|
23
|
+
def to_html(*rules,&callback)
|
24
|
+
@callback = callback
|
25
|
+
rules = DEFAULT_RULES if rules.empty?
|
26
|
+
text = super(*([:pre_wiki_words,:pre_make_divs,:post_add_toggle]+rules))
|
27
|
+
end
|
28
|
+
def htmlesc(str,mode)
|
29
|
+
super
|
30
|
+
str
|
31
|
+
end
|
32
|
+
# Bracket free text consists of either
|
33
|
+
# characters that are not "{" or "}",
|
34
|
+
# one or two "{"s, not followed by a third "{",
|
35
|
+
# one or two "}"s, not followed by a third "}",
|
36
|
+
#
|
37
|
+
BRACKET_FREE_TEXT = "((:?[^{}]|[{]{1,2}(?![{])|[}]{1,2}(?![}]))*?)"
|
38
|
+
DIV_BRACKETS = /\{\{\{#{BRACKET_FREE_TEXT}\}\}\}/m
|
39
|
+
ALT_TEXT = /
|
40
|
+
(
|
41
|
+
([\s\[{(]|[#{PUNCT}])? # $pre
|
42
|
+
" # start
|
43
|
+
(#{C}) # $atts
|
44
|
+
([^"]+?) # $text
|
45
|
+
\s?
|
46
|
+
(?:\(([^)]+?)\)(?="))? # $title
|
47
|
+
":
|
48
|
+
)?
|
49
|
+
/mx
|
50
|
+
XDIV_RE = /
|
51
|
+
(
|
52
|
+
([\s\[{(]|[#{PUNCT}])? # $pre
|
53
|
+
" # start
|
54
|
+
(#{C}) # $atts
|
55
|
+
([^"]+?) # $text
|
56
|
+
\s?
|
57
|
+
(?:\(([^)]+?)\)(?="))? # $title
|
58
|
+
":
|
59
|
+
)?
|
60
|
+
#{DIV_BRACKETS} # $div_block
|
61
|
+
/mx
|
62
|
+
DIV_RE = /#{ALT_TEXT}#{DIV_BRACKETS}/m
|
63
|
+
|
64
|
+
def pre_make_divs( text )
|
65
|
+
## break the text into <div> blocks based on {{{ ... }}}
|
66
|
+
while text.gsub!( DIV_RE ) { |m|
|
67
|
+
has_link,pre,atts,link_text,title,div_block = $~.captures
|
68
|
+
if has_link
|
69
|
+
@need_toggle_function = true
|
70
|
+
id = "div_#{rand(100000)}"
|
71
|
+
atts = shelve(" onclick=\"toggle('#{id}'); return false;\" #{ pba(atts) } title=\"#{ title||'more...' }\"")
|
72
|
+
"#{ pre }<a#{ atts }>#{ link_text }</a><div id=\"#{id}\" style=\"display:none\">#{div_block}</div>"
|
73
|
+
else
|
74
|
+
"<div #{shelve(attrs) }>#{div_block}</div>"
|
75
|
+
end
|
76
|
+
}; end
|
77
|
+
text
|
78
|
+
end
|
79
|
+
def post_add_toggle(text)
|
80
|
+
text << %q{
|
81
|
+
<script type="text/javascript" language="JavaScript">
|
82
|
+
<!--
|
83
|
+
function toggle(name) {
|
84
|
+
q=document.getElementById(name);
|
85
|
+
if (q.style.display == 'none')
|
86
|
+
{q.style.display = 'block';}
|
87
|
+
else
|
88
|
+
{q.style.display = 'none';};
|
89
|
+
}
|
90
|
+
//-->
|
91
|
+
</script>
|
92
|
+
} if @need_toggle_function
|
93
|
+
end
|
94
|
+
NOT_WIKI_WORD = /\\(([A-Z]+[a-z0-9]+){2,})/
|
95
|
+
WIKI_WORD = /#{ALT_TEXT}(([A-Z]+[a-z1-9]+){2,})/
|
96
|
+
WIKI_PHRASE = /#{ALT_TEXT}\[\[(.*?)\]\]/m
|
97
|
+
def split_wiki_word(ww)
|
98
|
+
ww.gsub(/([a-z0-9])([A-Z])/,'\1 \2');
|
99
|
+
end
|
100
|
+
def clean_wiki_word(ww)
|
101
|
+
ww.gsub(/[^A-Za-z0-9$-_.+!*'(),]/,'')
|
102
|
+
end
|
103
|
+
include ActionView::Helpers::TagHelper
|
104
|
+
include ActionView::Helpers::UrlHelper
|
105
|
+
def wiki_link(link_text,ww)
|
106
|
+
(@callback && @callback.call(:wiki_link,link_text,ww)) ||
|
107
|
+
(link_to link_text, "/<%= file_name %>/show/#{clean_wiki_word(ww)}")
|
108
|
+
end
|
109
|
+
def pre_wiki_words(text)
|
110
|
+
text.gsub!(NOT_WIKI_WORD) { |m| shelve $1 }
|
111
|
+
[WIKI_PHRASE,WIKI_WORD].each {|pattern|
|
112
|
+
text.gsub!(pattern) { |m|
|
113
|
+
has_link,pre,atts,link_text,title,ww = $~.captures
|
114
|
+
ww = split_wiki_word(ww) if pattern == WIKI_WORD
|
115
|
+
(pre||'') + shelve(wiki_link("<span #{pba(atts)}>#{link_text||ww}</span>",ww))
|
116
|
+
}
|
117
|
+
}
|
118
|
+
text
|
119
|
+
end
|
120
|
+
end
|
121
|
+
def textilize(body) #html
|
122
|
+
if body.blank?
|
123
|
+
""
|
124
|
+
else
|
125
|
+
RopaRojo.new(body, [:hard_breaks ]).to_html { |event,*details|
|
126
|
+
case event
|
127
|
+
when :wiki_link
|
128
|
+
link_text,ww = *details
|
129
|
+
page = (Page.find_by_title(ww) || Page.new_page(ww))
|
130
|
+
links << page unless links.include? page
|
131
|
+
nil
|
132
|
+
else
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
def html
|
139
|
+
sanitize_html(textilize(body))
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Page < ActiveRecord::Base
|
2
|
+
belongs_to :current_draft, :class_name => 'Draft', :foreign_key => :current_draft_id
|
3
|
+
has_many :drafts, :foreign_key => :draft_of_page_id
|
4
|
+
has_and_belongs_to_many :links,:class_name => "Draft",:join_table => 'links'
|
5
|
+
belongs_to :author, :class_name => 'User', :foreign_key => :created_by
|
6
|
+
validates_uniqueness_of :title, :on => :create
|
7
|
+
validates_length_of :title, :within => 1..80
|
8
|
+
validates_presence_of :title
|
9
|
+
def self.new_page(title)
|
10
|
+
p = Page.new :created_by => User.current_user, :title => title
|
11
|
+
p.raw = ''
|
12
|
+
p
|
13
|
+
end
|
14
|
+
def raw
|
15
|
+
current_draft && current_draft.raw
|
16
|
+
end
|
17
|
+
def raw=(new_text)
|
18
|
+
d = Draft.new(
|
19
|
+
:body => new_text || '',
|
20
|
+
:based_on_draft_id => self.current_draft && self.current_draft.id,
|
21
|
+
:created_by => User.current_user
|
22
|
+
);
|
23
|
+
d.save;
|
24
|
+
self.current_draft = d
|
25
|
+
self.drafts << d
|
26
|
+
new_text
|
27
|
+
end
|
28
|
+
def html
|
29
|
+
current_draft.html
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h1>Listing pages</h1>
|
2
|
+
|
3
|
+
<table>
|
4
|
+
<tr><th>Title</th><th>Created by</th><th>on</th><th>Revised by</th><th>on</th>
|
5
|
+
</tr>
|
6
|
+
|
7
|
+
<%% for page in @pages %>
|
8
|
+
<tr>
|
9
|
+
<td><%%= link_to page.title, :action => 'show', :id => page.title %></td>
|
10
|
+
<td><%%= page.author.login %></td>
|
11
|
+
<td><%%= page.created_on %></td>
|
12
|
+
<td><%%= page.current_draft.author.login %></td>
|
13
|
+
<td><%%= page.current_draft.created_on %></td>
|
14
|
+
</tr>
|
15
|
+
<%% end %>
|
16
|
+
</table>
|
17
|
+
|
18
|
+
<%%= link_to 'Previous page', { :page => @page_pages.current.previous } if @page_pages.current.previous %>
|
19
|
+
<%%= link_to 'Next page', { :page => @page_pages.current.next } if @page_pages.current.next %>
|
20
|
+
|
21
|
+
<br />
|
22
|
+
|
23
|
+
<%%= link_to 'New page', :action => 'create' %>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<h1><%%= @page.title %></h1>
|
2
|
+
|
3
|
+
<div style='background: #EFE; width: 80%; padding: 1ex 2ex 1ex 2ex'>
|
4
|
+
<%%= @page.html %>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
|
8
|
+
Created by <%%= @page.author.login %> on <%%= @page.created_on %><br>
|
9
|
+
Revised by <%%= @page.current_draft.author.login %> on <%%= @page.current_draft.created_on %><br>
|
10
|
+
Referenced from: <%% @page.links.each do |link| %>
|
11
|
+
<%% if link.id == link.page.current_draft.id %>
|
12
|
+
<%%= link_to link.page.title, :action => 'show', :id => link.page.title %>
|
13
|
+
<%% end %>
|
14
|
+
<%% end %>
|
15
|
+
<br>
|
16
|
+
<%%= link_to 'Edit', :action => 'edit', :id => @page.title %> |
|
17
|
+
<%%= link_to 'List All Pages', :action => 'list' %>
|
18
|
+
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: sqliki
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.3
|
7
|
+
date: 2005-08-25
|
8
|
+
summary: "[Rails] SQL-based wiki generator."
|
9
|
+
require_paths:
|
10
|
+
- "."
|
11
|
+
email: Markus@reality.com
|
12
|
+
homepage: http://www.rubyonrails.org/show/Generators
|
13
|
+
rubyforge_project:
|
14
|
+
description: Generates code for (primative) a SQL-based wiki within your Rails app.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Markus J. Q. Roberts
|
29
|
+
files:
|
30
|
+
- USAGE
|
31
|
+
- templates/lib_sanitize_html.rb
|
32
|
+
- templates/README
|
33
|
+
- templates/model_draft.rb
|
34
|
+
- templates/view_edit.rhtml
|
35
|
+
- templates/view__form.rhtml
|
36
|
+
- templates/view_inplace_edit.rhtml
|
37
|
+
- templates/view_list.rhtml
|
38
|
+
- templates/view_create.rhtml
|
39
|
+
- templates/view_rollback.rhtml
|
40
|
+
- templates/view_show.rhtml
|
41
|
+
- templates/model_link.rb
|
42
|
+
- templates/model_page.rb
|
43
|
+
- templates/controller_sqliki_controller.rb
|
44
|
+
- sqliki_generator.rb
|
45
|
+
- sqliki_generator-0.0.3.gemspec
|
46
|
+
test_files: []
|
47
|
+
rdoc_options: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
requirements: []
|
52
|
+
dependencies:
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rails
|
55
|
+
version_requirement:
|
56
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
57
|
+
requirements:
|
58
|
+
-
|
59
|
+
- ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.13.1
|
62
|
+
version:
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: RedCloth
|
65
|
+
version_requirement:
|
66
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
67
|
+
requirements:
|
68
|
+
-
|
69
|
+
- ">"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 0.0.0
|
72
|
+
version:
|