instiki 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/CHANGELOG +174 -165
  2. data/README +68 -68
  3. data/app/controllers/admin_controller.rb +94 -94
  4. data/app/controllers/application.rb +135 -131
  5. data/app/controllers/file_controller.rb +129 -129
  6. data/app/controllers/wiki_controller.rb +354 -354
  7. data/app/helpers/application_helper.rb +68 -68
  8. data/app/models/author.rb +3 -3
  9. data/app/models/chunks/category.rb +33 -33
  10. data/app/models/chunks/chunk.rb +86 -86
  11. data/app/models/chunks/engines.rb +61 -54
  12. data/app/models/chunks/include.rb +41 -41
  13. data/app/models/chunks/literal.rb +31 -31
  14. data/app/models/chunks/nowiki.rb +28 -28
  15. data/app/models/chunks/test.rb +18 -18
  16. data/app/models/chunks/uri.rb +182 -182
  17. data/app/models/chunks/wiki.rb +141 -141
  18. data/app/models/file_yard.rb +58 -58
  19. data/app/models/page.rb +112 -112
  20. data/app/models/page_lock.rb +22 -22
  21. data/app/models/page_set.rb +89 -89
  22. data/app/models/revision.rb +123 -123
  23. data/app/models/web.rb +182 -176
  24. data/app/models/wiki_content.rb +207 -207
  25. data/app/models/wiki_service.rb +233 -233
  26. data/app/models/wiki_words.rb +23 -23
  27. data/app/views/admin/create_system.rhtml +83 -83
  28. data/app/views/admin/create_web.rhtml +69 -69
  29. data/app/views/admin/edit_web.rhtml +137 -136
  30. data/app/views/file/file.rhtml +18 -18
  31. data/app/views/file/import.rhtml +22 -22
  32. data/app/views/layouts/default.rhtml +86 -85
  33. data/app/views/markdown_help.rhtml +12 -12
  34. data/app/views/mixed_help.rhtml +6 -6
  35. data/app/views/navigation.rhtml +30 -30
  36. data/app/views/rdoc_help.rhtml +12 -12
  37. data/app/views/textile_help.rhtml +24 -24
  38. data/app/views/wiki/authors.rhtml +11 -11
  39. data/app/views/wiki/edit.rhtml +39 -39
  40. data/app/views/wiki/export.rhtml +12 -12
  41. data/app/views/wiki/feeds.rhtml +14 -14
  42. data/app/views/wiki/list.rhtml +64 -64
  43. data/app/views/wiki/locked.rhtml +23 -23
  44. data/app/views/wiki/login.rhtml +14 -14
  45. data/app/views/wiki/new.rhtml +31 -31
  46. data/app/views/wiki/page.rhtml +115 -115
  47. data/app/views/wiki/print.rhtml +14 -14
  48. data/app/views/wiki/published.rhtml +9 -9
  49. data/app/views/wiki/recently_revised.rhtml +26 -26
  50. data/app/views/wiki/revision.rhtml +103 -103
  51. data/app/views/wiki/rollback.rhtml +36 -36
  52. data/app/views/wiki/rss_feed.rhtml +22 -22
  53. data/app/views/wiki/search.rhtml +38 -38
  54. data/app/views/wiki/tex.rhtml +22 -22
  55. data/app/views/wiki/tex_web.rhtml +34 -34
  56. data/app/views/wiki/web_list.rhtml +18 -18
  57. data/app/views/wiki_words_help.rhtml +9 -9
  58. data/config/environment.rb +82 -82
  59. data/config/environments/development.rb +5 -5
  60. data/config/environments/production.rb +4 -4
  61. data/config/environments/test.rb +17 -17
  62. data/config/routes.rb +18 -18
  63. data/lib/active_record_stub.rb +31 -31
  64. data/lib/bluecloth_tweaked.rb +1127 -0
  65. data/lib/diff.rb +444 -444
  66. data/lib/instiki_errors.rb +14 -14
  67. data/lib/rdocsupport.rb +151 -151
  68. data/lib/redcloth_for_tex.rb +736 -736
  69. data/natives/osx/desktop_launcher/AppDelegate.h +18 -18
  70. data/natives/osx/desktop_launcher/AppDelegate.mm +109 -109
  71. data/natives/osx/desktop_launcher/Credits.html +15 -15
  72. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +12 -12
  73. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -24
  74. data/natives/osx/desktop_launcher/Info.plist +12 -12
  75. data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -592
  76. data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -7
  77. data/natives/osx/desktop_launcher/MakeDMG.sh +9 -9
  78. data/natives/osx/desktop_launcher/main.mm +14 -14
  79. data/natives/osx/desktop_launcher/version.plist +16 -16
  80. data/public/404.html +5 -5
  81. data/public/500.html +5 -5
  82. data/public/dispatch.rb +9 -9
  83. data/public/javascripts/edit_web.js +52 -52
  84. data/public/javascripts/prototype.js +336 -336
  85. data/public/stylesheets/instiki.css +222 -222
  86. data/script/breakpointer +4 -4
  87. data/script/server +93 -93
  88. metadata +4 -3
@@ -1,68 +1,68 @@
1
- # The methods added to this helper will be available to all templates in the application.
2
- module ApplicationHelper
3
-
4
- # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
5
- # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
6
- # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
7
- # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag.
8
- #
9
- # Examples (call, result):
10
- # html_options([["Dollar", "$"], ["Kroner", "DKK"]])
11
- # <option value="$">Dollar</option>\n<option value="DKK">Kroner</option>
12
- #
13
- # html_options([ "VISA", "Mastercard" ], "Mastercard")
14
- # <option>VISA</option>\n<option selected>Mastercard</option>
15
- #
16
- # html_options({ "Basic" => "$20", "Plus" => "$40" }, "$40")
17
- # <option value="$20">Basic</option>\n<option value="$40" selected>Plus</option>
18
- def html_options(container, selected = nil)
19
- container = container.to_a if Hash === container
20
-
21
- html_options = container.inject([]) do |options, element|
22
- if element.respond_to?(:first) && element.respond_to?(:last)
23
- if element.last != selected
24
- options << "<option value=\"#{element.last}\">#{element.first}</option>"
25
- else
26
- options << "<option value=\"#{element.last}\" selected>#{element.first}</option>"
27
- end
28
- else
29
- options << ((element != selected) ? "<option>#{element}</option>" : "<option selected>#{element}</option>")
30
- end
31
- end
32
-
33
- html_options.join("\n")
34
- end
35
-
36
- # Creates a hyperlink to a Wiki page, without checking if the page exists or not
37
- def link_to_existing_page(page, text = nil, html_options = {})
38
- link_to(
39
- text || page.name,
40
- {:web => @web.address, :action => 'show', :id => page.name, :only_path => true},
41
- html_options)
42
- end
43
-
44
-
45
- # Creates a hyperlink to a Wiki page, or to a "new page" form if the page doesn't exist yet
46
- def link_to_page(page_name, web = @web, text = nil, options = {})
47
- raise 'Web not defined' if web.nil?
48
- home_page_url = url_for :web => web.address, :action => 'show', :id => 'HomePage', :only_path => true
49
- base_url = home_page_url.sub(%r-/show/HomePage/?$-, '')
50
- web.make_link(page_name, text, options.merge(:base_url => base_url))
51
- end
52
-
53
- # Creates a menu of categories
54
- def categories_menu
55
- if @categories.empty?
56
- ''
57
- else
58
- "<div id=\"categories\">\n" +
59
- '<strong>Categories</strong>:' +
60
- '[' + link_to_unless_current('Any', :web => @web.address, :action => @action_name) + "]\n" +
61
- @categories.map { |c|
62
- link_to_unless_current(c, :web => @web.address, :action => @action_name, :category => c)
63
- }.join(', ') + "\n" +
64
- '</div>'
65
- end
66
- end
67
-
68
- end
1
+ # The methods added to this helper will be available to all templates in the application.
2
+ module ApplicationHelper
3
+
4
+ # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
5
+ # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
6
+ # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
7
+ # become lasts. If +selected+ is specified, the matching "last" or element will get the selected option-tag.
8
+ #
9
+ # Examples (call, result):
10
+ # html_options([["Dollar", "$"], ["Kroner", "DKK"]])
11
+ # <option value="$">Dollar</option>\n<option value="DKK">Kroner</option>
12
+ #
13
+ # html_options([ "VISA", "Mastercard" ], "Mastercard")
14
+ # <option>VISA</option>\n<option selected>Mastercard</option>
15
+ #
16
+ # html_options({ "Basic" => "$20", "Plus" => "$40" }, "$40")
17
+ # <option value="$20">Basic</option>\n<option value="$40" selected>Plus</option>
18
+ def html_options(container, selected = nil)
19
+ container = container.to_a if Hash === container
20
+
21
+ html_options = container.inject([]) do |options, element|
22
+ if element.respond_to?(:first) && element.respond_to?(:last)
23
+ if element.last != selected
24
+ options << "<option value=\"#{element.last}\">#{element.first}</option>"
25
+ else
26
+ options << "<option value=\"#{element.last}\" selected>#{element.first}</option>"
27
+ end
28
+ else
29
+ options << ((element != selected) ? "<option>#{element}</option>" : "<option selected>#{element}</option>")
30
+ end
31
+ end
32
+
33
+ html_options.join("\n")
34
+ end
35
+
36
+ # Creates a hyperlink to a Wiki page, without checking if the page exists or not
37
+ def link_to_existing_page(page, text = nil, html_options = {})
38
+ link_to(
39
+ text || page.name,
40
+ {:web => @web.address, :action => 'show', :id => page.name, :only_path => true},
41
+ html_options)
42
+ end
43
+
44
+
45
+ # Creates a hyperlink to a Wiki page, or to a "new page" form if the page doesn't exist yet
46
+ def link_to_page(page_name, web = @web, text = nil, options = {})
47
+ raise 'Web not defined' if web.nil?
48
+ home_page_url = url_for :web => web.address, :action => 'show', :id => 'HomePage', :only_path => true
49
+ base_url = home_page_url.sub(%r-/show/HomePage/?$-, '')
50
+ web.make_link(page_name, text, options.merge(:base_url => base_url))
51
+ end
52
+
53
+ # Creates a menu of categories
54
+ def categories_menu
55
+ if @categories.empty?
56
+ ''
57
+ else
58
+ "<div id=\"categories\">\n" +
59
+ '<strong>Categories</strong>:' +
60
+ '[' + link_to_unless_current('Any', :web => @web.address, :action => @action_name) + "]\n" +
61
+ @categories.map { |c|
62
+ link_to_unless_current(c, :web => @web.address, :action => @action_name, :category => c)
63
+ }.join(', ') + "\n" +
64
+ '</div>'
65
+ end
66
+ end
67
+
68
+ end
data/app/models/author.rb CHANGED
@@ -1,4 +1,4 @@
1
- class Author < String
2
- attr_accessor :ip
3
- def initialize(name, ip) @ip = ip; super(name) end
1
+ class Author < String
2
+ attr_accessor :ip
3
+ def initialize(name, ip) @ip = ip; super(name) end
4
4
  end
@@ -1,33 +1,33 @@
1
- require 'chunks/chunk'
2
-
3
- # The category chunk looks for "category: news" on a line by
4
- # itself and parses the terms after the ':' as categories.
5
- # Other classes can search for Category chunks within
6
- # rendered content to find out what categories this page
7
- # should be in.
8
- #
9
- # Category lines can be hidden using ':category: news', for example
10
- class Category < Chunk::Abstract
11
- CATEGORY_PATTERN = /^(:)?category\s*:(.*)$/i
12
- def self.pattern() CATEGORY_PATTERN end
13
-
14
- attr_reader :hidden, :list
15
-
16
- def initialize(match_data, content)
17
- super(match_data, content)
18
- @hidden = match_data[1]
19
- @list = match_data[2].split(',').map { |c| c.strip }
20
- @unmask_text = ''
21
- if @hidden
22
- @unmask_text = ''
23
- else
24
- category_urls = @list.map { |category| url(category) }.join(', ')
25
- @unmask_text = '<div class="property"> category: ' + category_urls + '</div>'
26
- end
27
- end
28
-
29
- # TODO move presentation of page metadata to controller/view
30
- def url(category)
31
- %{<a class="category_link" href="../list/?category=#{category}">#{category}</a>}
32
- end
33
- end
1
+ require 'chunks/chunk'
2
+
3
+ # The category chunk looks for "category: news" on a line by
4
+ # itself and parses the terms after the ':' as categories.
5
+ # Other classes can search for Category chunks within
6
+ # rendered content to find out what categories this page
7
+ # should be in.
8
+ #
9
+ # Category lines can be hidden using ':category: news', for example
10
+ class Category < Chunk::Abstract
11
+ CATEGORY_PATTERN = /^(:)?category\s*:(.*)$/i
12
+ def self.pattern() CATEGORY_PATTERN end
13
+
14
+ attr_reader :hidden, :list
15
+
16
+ def initialize(match_data, content)
17
+ super(match_data, content)
18
+ @hidden = match_data[1]
19
+ @list = match_data[2].split(',').map { |c| c.strip }
20
+ @unmask_text = ''
21
+ if @hidden
22
+ @unmask_text = ''
23
+ else
24
+ category_urls = @list.map { |category| url(category) }.join(', ')
25
+ @unmask_text = '<div class="property"> category: ' + category_urls + '</div>'
26
+ end
27
+ end
28
+
29
+ # TODO move presentation of page metadata to controller/view
30
+ def url(category)
31
+ %{<a class="category_link" href="../list/?category=#{category}">#{category}</a>}
32
+ end
33
+ end
@@ -1,86 +1,86 @@
1
- require 'uri/common'
2
-
3
- # A chunk is a pattern of text that can be protected
4
- # and interrogated by a renderer. Each Chunk class has a
5
- # +pattern+ that states what sort of text it matches.
6
- # Chunks are initalized by passing in the result of a
7
- # match by its pattern.
8
-
9
- module Chunk
10
- class Abstract
11
-
12
- # automatically construct the array of derivatives of Chunk::Abstract
13
- @derivatives = []
14
-
15
- class << self
16
- attr_reader :derivatives
17
- end
18
-
19
- def self::inherited( klass )
20
- Abstract::derivatives << klass
21
- end
22
-
23
- # the class name part of the mask strings
24
- def self.mask_string
25
- self.to_s.delete(':').downcase
26
- end
27
-
28
- # a regexp that matches all chunk_types masks
29
- def Abstract::mask_re(chunk_types)
30
- tmp = chunk_types.map{|klass| klass.mask_string}.join("|")
31
- Regexp.new("chunk([0-9a-f]+n\\d+)(#{tmp})chunk")
32
- end
33
-
34
- attr_reader :text, :unmask_text, :unmask_mode
35
-
36
- def initialize(match_data, content)
37
- @text = match_data[0]
38
- @content = content
39
- @unmask_mode = :normal
40
- end
41
-
42
- # Find all the chunks of the given type in content
43
- # Each time the pattern is matched, create a new
44
- # chunk for it, and replace the occurance of the chunk
45
- # in this content with its mask.
46
- def self.apply_to(content)
47
- content.gsub!( self.pattern ) do |match|
48
- new_chunk = self.new($~, content)
49
- content.add_chunk(new_chunk)
50
- new_chunk.mask
51
- end
52
- end
53
-
54
- # should contain only [a-z0-9]
55
- def mask
56
- @mask ||="chunk#{@id}#{self.class.mask_string}chunk"
57
- end
58
-
59
- # We should not use object_id because object_id is not guarantied
60
- # to be unique when we restart the wiki (new object ids can equal old ones
61
- # that were restored form madeleine storage)
62
- def id
63
- @id ||= "#{@content.page_id}n#{@content.chunk_id}"
64
- end
65
-
66
- def unmask
67
- @content.sub!(mask, @unmask_text)
68
- end
69
-
70
- def rendered?
71
- @unmask_mode == :normal
72
- end
73
-
74
- def escaped?
75
- @unmask_mode == :escape
76
- end
77
-
78
- def revert
79
- @content.sub!(mask, @text)
80
- # unregister
81
- @content.delete_chunk(self)
82
- end
83
-
84
- end
85
-
86
- end
1
+ require 'uri/common'
2
+
3
+ # A chunk is a pattern of text that can be protected
4
+ # and interrogated by a renderer. Each Chunk class has a
5
+ # +pattern+ that states what sort of text it matches.
6
+ # Chunks are initalized by passing in the result of a
7
+ # match by its pattern.
8
+
9
+ module Chunk
10
+ class Abstract
11
+
12
+ # automatically construct the array of derivatives of Chunk::Abstract
13
+ @derivatives = []
14
+
15
+ class << self
16
+ attr_reader :derivatives
17
+ end
18
+
19
+ def self::inherited( klass )
20
+ Abstract::derivatives << klass
21
+ end
22
+
23
+ # the class name part of the mask strings
24
+ def self.mask_string
25
+ self.to_s.delete(':').downcase
26
+ end
27
+
28
+ # a regexp that matches all chunk_types masks
29
+ def Abstract::mask_re(chunk_types)
30
+ tmp = chunk_types.map{|klass| klass.mask_string}.join("|")
31
+ Regexp.new("chunk([0-9a-f]+n\\d+)(#{tmp})chunk")
32
+ end
33
+
34
+ attr_reader :text, :unmask_text, :unmask_mode
35
+
36
+ def initialize(match_data, content)
37
+ @text = match_data[0]
38
+ @content = content
39
+ @unmask_mode = :normal
40
+ end
41
+
42
+ # Find all the chunks of the given type in content
43
+ # Each time the pattern is matched, create a new
44
+ # chunk for it, and replace the occurance of the chunk
45
+ # in this content with its mask.
46
+ def self.apply_to(content)
47
+ content.gsub!( self.pattern ) do |match|
48
+ new_chunk = self.new($~, content)
49
+ content.add_chunk(new_chunk)
50
+ new_chunk.mask
51
+ end
52
+ end
53
+
54
+ # should contain only [a-z0-9]
55
+ def mask
56
+ @mask ||="chunk#{@id}#{self.class.mask_string}chunk"
57
+ end
58
+
59
+ # We should not use object_id because object_id is not guarantied
60
+ # to be unique when we restart the wiki (new object ids can equal old ones
61
+ # that were restored form madeleine storage)
62
+ def id
63
+ @id ||= "#{@content.page_id}n#{@content.chunk_id}"
64
+ end
65
+
66
+ def unmask
67
+ @content.sub!(mask, @unmask_text)
68
+ end
69
+
70
+ def rendered?
71
+ @unmask_mode == :normal
72
+ end
73
+
74
+ def escaped?
75
+ @unmask_mode == :escape
76
+ end
77
+
78
+ def revert
79
+ @content.sub!(mask, @text)
80
+ # unregister
81
+ @content.delete_chunk(self)
82
+ end
83
+
84
+ end
85
+
86
+ end
@@ -1,54 +1,61 @@
1
- $: << File.dirname(__FILE__) + "../../lib"
2
-
3
- require 'redcloth'
4
- require 'rdocsupport'
5
- require 'chunks/chunk'
6
-
7
- # The markup engines are Chunks that call the one of RedCloth
8
- # or RDoc to convert text. This markup occurs when the chunk is required
9
- # to mask itself.
10
- module Engines
11
- class AbstractEngine < Chunk::Abstract
12
-
13
- # Create a new chunk for the whole content and replace it with its mask.
14
- def self.apply_to(content)
15
- new_chunk = self.new(content)
16
- content.replace(new_chunk.mask)
17
- end
18
-
19
- private
20
-
21
- # Never create engines by constructor - use apply_to instead
22
- def initialize(content)
23
- @content = content
24
- end
25
-
26
- end
27
-
28
- class Textile < AbstractEngine
29
- def mask
30
- RedCloth.new(@content, @content.options[:engine_opts]).to_html(:textile)
31
- end
32
- end
33
-
34
- class Markdown < AbstractEngine
35
- def mask
36
- RedCloth.new(@content, @content.options[:engine_opts]).to_html(:markdown)
37
- end
38
- end
39
-
40
- class Mixed < AbstractEngine
41
- def mask
42
- RedCloth.new(@content, @content.options[:engine_opts]).to_html
43
- end
44
- end
45
-
46
- class RDoc < AbstractEngine
47
- def mask
48
- RDocSupport::RDocFormatter.new(@content).to_html
49
- end
50
- end
51
-
52
- MAP = { :textile => Textile, :markdown => Markdown, :mixed => Mixed, :rdoc => RDoc, }
53
- MAP.default = Textile
54
- end
1
+ $: << File.dirname(__FILE__) + "../../lib"
2
+
3
+ require 'redcloth'
4
+ require 'bluecloth_tweaked'
5
+ require 'rdocsupport'
6
+ require 'chunks/chunk'
7
+
8
+ # The markup engines are Chunks that call the one of RedCloth
9
+ # or RDoc to convert text. This markup occurs when the chunk is required
10
+ # to mask itself.
11
+ module Engines
12
+ class AbstractEngine < Chunk::Abstract
13
+
14
+ # Create a new chunk for the whole content and replace it with its mask.
15
+ def self.apply_to(content)
16
+ new_chunk = self.new(content)
17
+ content.replace(new_chunk.mask)
18
+ end
19
+
20
+ private
21
+
22
+ # Never create engines by constructor - use apply_to instead
23
+ def initialize(content)
24
+ @content = content
25
+ end
26
+
27
+ end
28
+
29
+ class Textile < AbstractEngine
30
+ def mask
31
+ redcloth = RedCloth.new(@content, [:hard_breaks] + @content.options[:engine_opts])
32
+ redcloth.filter_html = false
33
+ redcloth.no_span_caps = false
34
+ redcloth.to_html(:textile)
35
+ end
36
+ end
37
+
38
+ class Markdown < AbstractEngine
39
+ def mask
40
+ BlueCloth.new(@content, @content.options[:engine_opts]).to_html
41
+ end
42
+ end
43
+
44
+ class Mixed < AbstractEngine
45
+ def mask
46
+ redcloth = RedCloth.new(@content, @content.options[:engine_opts])
47
+ redcloth.filter_html = false
48
+ redcloth.no_span_caps = false
49
+ redcloth.to_html
50
+ end
51
+ end
52
+
53
+ class RDoc < AbstractEngine
54
+ def mask
55
+ RDocSupport::RDocFormatter.new(@content).to_html
56
+ end
57
+ end
58
+
59
+ MAP = { :textile => Textile, :markdown => Markdown, :mixed => Mixed, :rdoc => RDoc }
60
+ MAP.default = Textile
61
+ end