sqliki_generator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/USAGE +46 -0
- data/sqliki_generator-0.0.1.gemspec +40 -0
- data/sqliki_generator.rb +39 -0
- data/templates/README +88 -0
- data/templates/controller_sqliki_controller.rb +77 -0
- data/templates/lib_sanitize_html.rb +143 -0
- data/templates/model_draft.rb +145 -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_edit.rhtml +9 -0
- data/templates/view_find.rhtml +2 -0
- data/templates/view_inplace_edit.rhtml +2 -0
- data/templates/view_inplace_save.rhtml +2 -0
- data/templates/view_list.rhtml +26 -0
- data/templates/view_new.rhtml +8 -0
- data/templates/view_rollback.rhtml +2 -0
- data/templates/view_show.rhtml +18 -0
- metadata +64 -0
data/USAGE
ADDED
@@ -0,0 +1,46 @@
|
|
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
|
+
Included:
|
13
|
+
- a User model which uses sha1 encryption for passwords
|
14
|
+
- a Controller with signup, login, welcome and logoff actions
|
15
|
+
- a mixin which lets you easily add advanced authentication
|
16
|
+
features to your abstract base controller
|
17
|
+
- a user_model.sql with the minimal sql required to get the model to work.
|
18
|
+
- extensive unit and functional test cases to make sure nothing breaks.
|
19
|
+
|
20
|
+
EXAMPLE
|
21
|
+
./script/generate sqliki Wiki
|
22
|
+
|
23
|
+
This will generate a Wiki controller with the following methods:
|
24
|
+
|
25
|
+
For users:
|
26
|
+
index (=list)
|
27
|
+
rollback
|
28
|
+
wanted
|
29
|
+
orphaned
|
30
|
+
recently_revised
|
31
|
+
find
|
32
|
+
list
|
33
|
+
show
|
34
|
+
new
|
35
|
+
edit
|
36
|
+
For control flow:
|
37
|
+
save
|
38
|
+
raw
|
39
|
+
html
|
40
|
+
inplace_edit
|
41
|
+
inplace_save
|
42
|
+
create
|
43
|
+
update
|
44
|
+
destroy
|
45
|
+
|
46
|
+
The tables are always called pages, drafts, and links
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
SPEC = Gem::Specification.new do |s|
|
4
|
+
s.name = %q{sqliki_generator}
|
5
|
+
s.version = "0.0.1"
|
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_find.rhtml
|
20
|
+
templates/view__form.rhtml
|
21
|
+
templates/view_inplace_edit.rhtml
|
22
|
+
templates/view_inplace_save.rhtml
|
23
|
+
templates/view_list.rhtml
|
24
|
+
templates/view_new.rhtml
|
25
|
+
templates/view_rollback.rhtml
|
26
|
+
templates/view_show.rhtml
|
27
|
+
templates/model_link.rb
|
28
|
+
templates/model_page.rb
|
29
|
+
templates/controller_sqliki_controller.rb
|
30
|
+
sqliki_generator.rb
|
31
|
+
sqliki_generator-0.0.1.gemspec
|
32
|
+
}
|
33
|
+
s.add_dependency(%q<rails>, [">= 0.13.1"])
|
34
|
+
end
|
35
|
+
|
36
|
+
if $0 == __FILE__
|
37
|
+
Gem::manage_gems
|
38
|
+
Gem::Builder.new(SPEC).build
|
39
|
+
end
|
40
|
+
|
data/sqliki_generator.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class SqlikiGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
|
5
|
+
#
|
6
|
+
# For v0.0.1, there's no renaming it
|
7
|
+
file_name = 'sqliki'
|
8
|
+
|
9
|
+
# Models.
|
10
|
+
%w{page draft link}.each do |x|
|
11
|
+
m.template "model_#{x}.rb",File.join("app/models", class_path, "#{x}.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
# Views.
|
15
|
+
m.directory File.join("app/views", class_path, file_name)
|
16
|
+
%w{edit find _form inplace_edit inplace_save list new rollback show }.each do |x|
|
17
|
+
m.template "view_#{x}.rhtml",File.join("app/views", class_path, file_name, "#{x}.rhtml")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Controller.
|
21
|
+
%w{sqliki}.each do |x|
|
22
|
+
m.template "controller_#{x}_controller.rb",File.join("app/controllers", class_path, "#{x}_controller.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
# Libs.
|
26
|
+
%w{sanitize_html}.each do |x|
|
27
|
+
m.template "lib_#{x}.rb",File.join("lib", class_path, "#{x}.rb")
|
28
|
+
end
|
29
|
+
|
30
|
+
m.template "README", "README_SQLIKI"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_accessor :controller_class_name
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
data/templates/README
ADDED
@@ -0,0 +1,88 @@
|
|
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 First gem release
|
88
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class SqlikiController < ApplicationController
|
2
|
+
model :draft
|
3
|
+
include LoginSystem
|
4
|
+
before_filter :login_required
|
5
|
+
def identify_page
|
6
|
+
@page ||= Page.find_by_title(params[:id]) #|| Page.find_by_id(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 inplace_edit
|
19
|
+
edit
|
20
|
+
end
|
21
|
+
def rollback
|
22
|
+
identify_page
|
23
|
+
#@page.current_draft = ???
|
24
|
+
render :action => 'show'
|
25
|
+
end
|
26
|
+
def save
|
27
|
+
end
|
28
|
+
def inplace_save
|
29
|
+
save
|
30
|
+
end
|
31
|
+
def wanted
|
32
|
+
end
|
33
|
+
def orphaned
|
34
|
+
end
|
35
|
+
def recently_revised
|
36
|
+
end
|
37
|
+
def find
|
38
|
+
end
|
39
|
+
def list(condition=:all)
|
40
|
+
@page_pages, @pages = paginate :page, :per_page => 10
|
41
|
+
end
|
42
|
+
def show
|
43
|
+
identify_page || redirect_to(:action => 'new', :id => @params[:id])
|
44
|
+
end
|
45
|
+
def new
|
46
|
+
@page = Page.new_page(@params[:id])
|
47
|
+
end
|
48
|
+
def create
|
49
|
+
new
|
50
|
+
@page.save
|
51
|
+
if @page.update_attributes(params[:page])
|
52
|
+
#@page.current_draft.created_by = @session[:user]
|
53
|
+
#@page.save
|
54
|
+
flash[:notice] = 'Page was successfully created.'
|
55
|
+
redirect_to :action => 'list'
|
56
|
+
else
|
57
|
+
render :action => 'new'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
def edit
|
61
|
+
identify_page || redirect_to(:action => 'new', :id => @params[:id])
|
62
|
+
end
|
63
|
+
def update
|
64
|
+
identify_page
|
65
|
+
if @page.update_attributes(params[:page])
|
66
|
+
flash[:notice] = 'Page was successfully updated.'
|
67
|
+
redirect_to :action => 'show', :id => @page.title
|
68
|
+
else
|
69
|
+
render :action => 'edit'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
def destroy
|
73
|
+
identify_page.destroy
|
74
|
+
redirect_to :action => 'list'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -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,145 @@
|
|
1
|
+
require 'sanitize_html'
|
2
|
+
require '/usr/local/lib/ruby/gems/1.8/gems/RedCloth-3.0.3/lib/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
|
+
make_divs text
|
19
|
+
super
|
20
|
+
end
|
21
|
+
def to_html(*rules,&callback)
|
22
|
+
@callback = callback
|
23
|
+
rules = DEFAULT_RULES if rules.empty?
|
24
|
+
text = super(*([:inline_wiki_words]+rules))
|
25
|
+
text << %q{
|
26
|
+
<script type="text/javascript" language="JavaScript">
|
27
|
+
<!--
|
28
|
+
function toggle(name) {
|
29
|
+
q=document.getElementById(name);
|
30
|
+
if (q.style.display == 'none')
|
31
|
+
{q.style.display = 'block';}
|
32
|
+
else
|
33
|
+
{q.style.display = 'none';};
|
34
|
+
}
|
35
|
+
//-->
|
36
|
+
</script>
|
37
|
+
} if @need_toggle_function
|
38
|
+
text
|
39
|
+
end
|
40
|
+
def htmlesc(str,mode)
|
41
|
+
super
|
42
|
+
str
|
43
|
+
end
|
44
|
+
# Bracket free text consists of either
|
45
|
+
# characters that are not "{" or "}",
|
46
|
+
# one or two "{"s, not followed by a third "{",
|
47
|
+
# one or two "}"s, not followed by a third "}",
|
48
|
+
#
|
49
|
+
BRACKET_FREE_TEXT = "((:?[^{}]|[{]{1,2}(?![{])|[}]{1,2}(?![}]))*?)"
|
50
|
+
DIV_BRACKETS = /\{\{\{#{BRACKET_FREE_TEXT}\}\}\}/m
|
51
|
+
ALT_TEXT = /
|
52
|
+
(
|
53
|
+
([\s\[{(]|[#{PUNCT}])? # $pre
|
54
|
+
" # start
|
55
|
+
(#{C}) # $atts
|
56
|
+
([^"]+?) # $text
|
57
|
+
\s?
|
58
|
+
(?:\(([^)]+?)\)(?="))? # $title
|
59
|
+
":
|
60
|
+
)?
|
61
|
+
/mx
|
62
|
+
XDIV_RE = /
|
63
|
+
(
|
64
|
+
([\s\[{(]|[#{PUNCT}])? # $pre
|
65
|
+
" # start
|
66
|
+
(#{C}) # $atts
|
67
|
+
([^"]+?) # $text
|
68
|
+
\s?
|
69
|
+
(?:\(([^)]+?)\)(?="))? # $title
|
70
|
+
":
|
71
|
+
)?
|
72
|
+
#{DIV_BRACKETS} # $div_block
|
73
|
+
/mx
|
74
|
+
DIV_RE = /#{ALT_TEXT}#{DIV_BRACKETS}/m
|
75
|
+
|
76
|
+
def make_divs( text )
|
77
|
+
## break the text into <div> blocks based on {{{ ... }}}
|
78
|
+
while text.gsub!( DIV_RE ) { |m|
|
79
|
+
has_link,pre,atts,link_text,title,div_block = $~.captures
|
80
|
+
if has_link
|
81
|
+
@need_toggle_function = true
|
82
|
+
id = "div_#{rand(100000)}"
|
83
|
+
atts = shelve(" onclick=\"toggle('#{id}'); return false;\" #{ pba(atts) } title=\"#{ title||'more...' }\"")
|
84
|
+
"#{ pre }<a#{ atts }>#{ link_text }</a><div id=\"#{id}\" style=\"display:none\">#{div_block}</div>"
|
85
|
+
else
|
86
|
+
"<div #{shelve(attrs) }>#{div_block}</div>"
|
87
|
+
end
|
88
|
+
}; end
|
89
|
+
text
|
90
|
+
end
|
91
|
+
NOT_WIKI_WORD = /\\(([A-Z]+[a-z0-9]+){2,})/
|
92
|
+
WIKI_WORD = /#{ALT_TEXT}(([A-Z]+[a-z1-9]+){2,})/
|
93
|
+
WIKI_PHRASE = /#{ALT_TEXT}\[\[(.*?)\]\]/m
|
94
|
+
def split_wiki_word(ww)
|
95
|
+
ww.gsub(/([a-z0-9])([A-Z])/,'\1 \2');
|
96
|
+
end
|
97
|
+
def clean_wiki_word(ww)
|
98
|
+
ww.gsub(/ /,'_').gsub(/[^A-Za-z0-9$-_.+!*'(),]/,'')
|
99
|
+
end
|
100
|
+
include ActionView::Helpers::TagHelper
|
101
|
+
include ActionView::Helpers::UrlHelper
|
102
|
+
#def wiki_link(ww)
|
103
|
+
# #link_to ww, {:controller => 'sqliki', :action => 'show', :id => clean_wiki_word(ww)}
|
104
|
+
# link_to ww, "/sqliki/show/#{clean_wiki_word(ww)}"
|
105
|
+
# end
|
106
|
+
def wiki_link(link_text,ww)
|
107
|
+
#link_to link_text, {:controller => 'sqliki', :action => 'show', :id => clean_wiki_word(ww)}
|
108
|
+
#(@callback && @callback.call(:wiki_link,link_text,ww)) || (link_to link_text, "/sqliki/show/#{clean_wiki_word(ww)}")
|
109
|
+
(@callback && @callback.call(:wiki_link,link_text,ww))
|
110
|
+
(link_to link_text, "/sqliki/show/#{clean_wiki_word(ww)}")
|
111
|
+
end
|
112
|
+
def inline_wiki_words(text)
|
113
|
+
text.gsub!(NOT_WIKI_WORD) { |m| shelve $1 }
|
114
|
+
[WIKI_PHRASE,WIKI_WORD].each {|pattern|
|
115
|
+
text.gsub!(pattern) { |m|
|
116
|
+
has_link,pre,atts,link_text,title,ww = $~.captures
|
117
|
+
ww = split_wiki_word(ww) if pattern == WIKI_WORD
|
118
|
+
(pre||'') + wiki_link("<span #{shelve(pba(atts))}>#{link_text||ww}</span>"||ww,ww)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
text
|
122
|
+
end
|
123
|
+
end
|
124
|
+
#include ActionView::Helpers::TextHelper
|
125
|
+
def textilize(body) #html
|
126
|
+
if body.blank?
|
127
|
+
""
|
128
|
+
else
|
129
|
+
RopaRojo.new(body, [:hard_breaks ]).to_html { |event,*details|
|
130
|
+
case event
|
131
|
+
when :wiki_link
|
132
|
+
link_text,ww = *details
|
133
|
+
page = (Page.find_by_title(ww) || Page.new_page(ww))
|
134
|
+
links << page unless links.include? page
|
135
|
+
nil
|
136
|
+
else
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
def html
|
143
|
+
sanitize_html(textilize(body))
|
144
|
+
end
|
145
|
+
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,9 @@
|
|
1
|
+
<h1><%%= @page.title %></h1>
|
2
|
+
|
3
|
+
<%%= start_form_tag :action => 'update', :id => @page.title %>
|
4
|
+
<%%= render_partial 'form' %>
|
5
|
+
<%%= submit_tag 'Edit' %>
|
6
|
+
<%%= end_form_tag %>
|
7
|
+
|
8
|
+
<%%= link_to 'Show', :action => 'show', :id => @page.title %> |
|
9
|
+
<%%= link_to 'List', :action => 'list' %>
|
@@ -0,0 +1,26 @@
|
|
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><%%= 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
|
+
<td><%%= link_to 'Show', :action => 'show', :id => page.title %></td>
|
15
|
+
<td><%%= link_to 'Edit', :action => 'edit', :id => page.title %></td>
|
16
|
+
<td><%%= link_to 'Destroy', {:action => 'destroy', :id => page.title}, :confirm => 'Are you sure?' %></td>
|
17
|
+
</tr>
|
18
|
+
<%% end %>
|
19
|
+
</table>
|
20
|
+
|
21
|
+
<%%= link_to 'Previous page', { :page => @page_pages.current.previous } if @page_pages.current.previous %>
|
22
|
+
<%%= link_to 'Next page', { :page => @page_pages.current.next } if @page_pages.current.next %>
|
23
|
+
|
24
|
+
<br />
|
25
|
+
|
26
|
+
<%%= link_to 'New page', :action => 'new' %>
|
@@ -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,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: sqliki_generator
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
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_find.rhtml
|
36
|
+
- templates/view__form.rhtml
|
37
|
+
- templates/view_inplace_edit.rhtml
|
38
|
+
- templates/view_inplace_save.rhtml
|
39
|
+
- templates/view_list.rhtml
|
40
|
+
- templates/view_new.rhtml
|
41
|
+
- templates/view_rollback.rhtml
|
42
|
+
- templates/view_show.rhtml
|
43
|
+
- templates/model_link.rb
|
44
|
+
- templates/model_page.rb
|
45
|
+
- templates/controller_sqliki_controller.rb
|
46
|
+
- sqliki_generator.rb
|
47
|
+
- sqliki_generator-0.0.1.gemspec
|
48
|
+
test_files: []
|
49
|
+
rdoc_options: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
requirements: []
|
54
|
+
dependencies:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
version_requirement:
|
58
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
59
|
+
requirements:
|
60
|
+
-
|
61
|
+
- ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.13.1
|
64
|
+
version:
|