sqliki_generator 0.0.1
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 +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:
|