read-only-gollum 1.4.0

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.
Files changed (176) hide show
  1. data/Gemfile +4 -0
  2. data/HISTORY.md +102 -0
  3. data/Home.md +3 -0
  4. data/LICENSE +21 -0
  5. data/README.md +477 -0
  6. data/Rakefile +142 -0
  7. data/bin/read-only-gollum +126 -0
  8. data/docs/sanitization.md +32 -0
  9. data/lib/gollum.rb +41 -0
  10. data/lib/gollum/blob_entry.rb +78 -0
  11. data/lib/gollum/committer.rb +218 -0
  12. data/lib/gollum/file.rb +64 -0
  13. data/lib/gollum/frontend/app.rb +225 -0
  14. data/lib/gollum/frontend/public/css/dialog.css +141 -0
  15. data/lib/gollum/frontend/public/css/editor.css +537 -0
  16. data/lib/gollum/frontend/public/css/gollum.css +660 -0
  17. data/lib/gollum/frontend/public/css/ie7.css +69 -0
  18. data/lib/gollum/frontend/public/css/template.css +381 -0
  19. data/lib/gollum/frontend/public/images/icon-sprite.png +0 -0
  20. data/lib/gollum/frontend/public/javascript/editor/gollum.editor.js +1096 -0
  21. data/lib/gollum/frontend/public/javascript/editor/langs/asciidoc.js +167 -0
  22. data/lib/gollum/frontend/public/javascript/editor/langs/creole.js +104 -0
  23. data/lib/gollum/frontend/public/javascript/editor/langs/markdown.js +211 -0
  24. data/lib/gollum/frontend/public/javascript/editor/langs/org.js +173 -0
  25. data/lib/gollum/frontend/public/javascript/editor/langs/pod.js +111 -0
  26. data/lib/gollum/frontend/public/javascript/editor/langs/rdoc.js +74 -0
  27. data/lib/gollum/frontend/public/javascript/editor/langs/textile.js +175 -0
  28. data/lib/gollum/frontend/public/javascript/gollum.dialog.js +263 -0
  29. data/lib/gollum/frontend/public/javascript/gollum.js +161 -0
  30. data/lib/gollum/frontend/public/javascript/gollum.placeholder.js +54 -0
  31. data/lib/gollum/frontend/public/javascript/jquery.color.js +123 -0
  32. data/lib/gollum/frontend/public/javascript/jquery.js +7179 -0
  33. data/lib/gollum/frontend/templates/compare.mustache +38 -0
  34. data/lib/gollum/frontend/templates/create.mustache +17 -0
  35. data/lib/gollum/frontend/templates/edit.mustache +17 -0
  36. data/lib/gollum/frontend/templates/editor.mustache +116 -0
  37. data/lib/gollum/frontend/templates/error.mustache +8 -0
  38. data/lib/gollum/frontend/templates/history.mustache +58 -0
  39. data/lib/gollum/frontend/templates/layout.mustache +28 -0
  40. data/lib/gollum/frontend/templates/page.mustache +37 -0
  41. data/lib/gollum/frontend/templates/pages.mustache +35 -0
  42. data/lib/gollum/frontend/templates/search.mustache +36 -0
  43. data/lib/gollum/frontend/templates/searchbar.mustache +10 -0
  44. data/lib/gollum/frontend/views/compare.rb +94 -0
  45. data/lib/gollum/frontend/views/create.rb +48 -0
  46. data/lib/gollum/frontend/views/edit.rb +52 -0
  47. data/lib/gollum/frontend/views/editable.rb +13 -0
  48. data/lib/gollum/frontend/views/error.rb +7 -0
  49. data/lib/gollum/frontend/views/history.rb +44 -0
  50. data/lib/gollum/frontend/views/layout.rb +20 -0
  51. data/lib/gollum/frontend/views/page.rb +57 -0
  52. data/lib/gollum/frontend/views/pages.rb +19 -0
  53. data/lib/gollum/frontend/views/search.rb +20 -0
  54. data/lib/gollum/git_access.rb +248 -0
  55. data/lib/gollum/markup.rb +489 -0
  56. data/lib/gollum/page.rb +430 -0
  57. data/lib/gollum/pagination.rb +61 -0
  58. data/lib/gollum/sanitization.rb +174 -0
  59. data/lib/gollum/tex.rb +89 -0
  60. data/lib/gollum/web_sequence_diagram.rb +43 -0
  61. data/lib/gollum/wiki.rb +636 -0
  62. data/read-only-gollum.gemspec +224 -0
  63. data/templates/formatting.html +92 -0
  64. data/test/examples/empty.git/HEAD +1 -0
  65. data/test/examples/empty.git/config +5 -0
  66. data/test/examples/empty.git/description +1 -0
  67. data/test/examples/empty.git/hooks/applypatch-msg.sample +15 -0
  68. data/test/examples/empty.git/hooks/commit-msg.sample +24 -0
  69. data/test/examples/empty.git/hooks/post-commit.sample +8 -0
  70. data/test/examples/empty.git/hooks/post-receive.sample +15 -0
  71. data/test/examples/empty.git/hooks/post-update.sample +8 -0
  72. data/test/examples/empty.git/hooks/pre-applypatch.sample +14 -0
  73. data/test/examples/empty.git/hooks/pre-commit.sample +46 -0
  74. data/test/examples/empty.git/hooks/pre-rebase.sample +169 -0
  75. data/test/examples/empty.git/hooks/prepare-commit-msg.sample +36 -0
  76. data/test/examples/empty.git/hooks/update.sample +128 -0
  77. data/test/examples/empty.git/info/exclude +6 -0
  78. data/test/examples/empty.git/objects/info/.gitkeep +0 -0
  79. data/test/examples/empty.git/objects/pack/.gitkeep +0 -0
  80. data/test/examples/empty.git/refs/heads/.gitkeep +0 -0
  81. data/test/examples/lotr.git/COMMIT_EDITMSG +1 -0
  82. data/test/examples/lotr.git/HEAD +1 -0
  83. data/test/examples/lotr.git/ORIG_HEAD +1 -0
  84. data/test/examples/lotr.git/config +12 -0
  85. data/test/examples/lotr.git/description +1 -0
  86. data/test/examples/lotr.git/index +0 -0
  87. data/test/examples/lotr.git/info/exclude +6 -0
  88. data/test/examples/lotr.git/logs/HEAD +3 -0
  89. data/test/examples/lotr.git/logs/refs/heads/master +3 -0
  90. data/test/examples/lotr.git/objects/06/131480411710c92a82fe2d1e76932c70feb2e5 +0 -0
  91. data/test/examples/lotr.git/objects/0a/de1e2916346d4c1f2fb63b863fd3c16808fe44 +0 -0
  92. data/test/examples/lotr.git/objects/0e/d8cbe0a25235bd867e65193c7d837c66b328ef +3 -0
  93. data/test/examples/lotr.git/objects/12/629d666c5e3178f82f533f543d61b53dc78c0b +0 -0
  94. data/test/examples/lotr.git/objects/1d/b89ebba7e2c14d93b94ff98cfa3708a4f0d4e3 +2 -0
  95. data/test/examples/lotr.git/objects/24/49c2681badfd3c189e8ed658dacffe8ba48fe5 +0 -0
  96. data/test/examples/lotr.git/objects/25/4bdc1ba27d8b8a794538a8522d9a2b56ec2dd9 +0 -0
  97. data/test/examples/lotr.git/objects/2c/b9156ad383914561a8502fc70f5a1d887e48ad +4 -0
  98. data/test/examples/lotr.git/objects/5d/cac289a8603188d2c5caf481dcba2985126aaa +0 -0
  99. data/test/examples/lotr.git/objects/60/f12f4254f58801b9ee7db7bca5fa8aeefaa56b +0 -0
  100. data/test/examples/lotr.git/objects/71/4323c104239440a5c66ab12a67ed07a83c404f +0 -0
  101. data/test/examples/lotr.git/objects/84/0ec5b1ba1320e8ec443f28f99566f615d5af10 +0 -0
  102. data/test/examples/lotr.git/objects/93/6b83ee0dd8837adb82511e40d5e4ebe59bb675 +0 -0
  103. data/test/examples/lotr.git/objects/94/523d7ae48aeba575099dd12926420d8fd0425d +2 -0
  104. data/test/examples/lotr.git/objects/96/97dc65e095658bbd1b8e8678e08881e86d32f1 +0 -0
  105. data/test/examples/lotr.git/objects/a3/1ca2a7c352c92531a8b99815d15843b259e814 +0 -0
  106. data/test/examples/lotr.git/objects/a6/59b3763b822dd97544621fd0beef162ea37b14 +4 -0
  107. data/test/examples/lotr.git/objects/a8/ad3c09dd842a3517085bfadd37718856dee813 +0 -0
  108. data/test/examples/lotr.git/objects/aa/b61fe89d56f8614c0a8151da34f939dcedfa68 +0 -0
  109. data/test/examples/lotr.git/objects/bc/4b5fc0ce2c2ba3acef6647e4f67256ee45ab60 +0 -0
  110. data/test/examples/lotr.git/objects/c3/b43e9f08966b088e7a0192e436b7a884542e05 +0 -0
  111. data/test/examples/lotr.git/objects/dc/596d6b2dd89ab05c66f4abd7d5eb706bc17f19 +0 -0
  112. data/test/examples/lotr.git/objects/ec/da3205bee14520aab5a7bb307392064b938e83 +0 -0
  113. data/test/examples/lotr.git/objects/f4/84ebb1f40f8eb20d1bcd8d1d71934d2b8ae961 +0 -0
  114. data/test/examples/lotr.git/objects/fa/e7ef5344202bba4129abdc13060d9297d99465 +3 -0
  115. data/test/examples/lotr.git/objects/info/packs +2 -0
  116. data/test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.idx +0 -0
  117. data/test/examples/lotr.git/objects/pack/pack-dcbeaf3f6ff6c5eb08ea2b0a2d83626e8763546b.pack +0 -0
  118. data/test/examples/lotr.git/packed-refs +2 -0
  119. data/test/examples/lotr.git/refs/heads/master +1 -0
  120. data/test/examples/lotr.git/refs/remotes/origin/HEAD +1 -0
  121. data/test/examples/page_file_dir.git/COMMIT_EDITMSG +1 -0
  122. data/test/examples/page_file_dir.git/HEAD +1 -0
  123. data/test/examples/page_file_dir.git/config +6 -0
  124. data/test/examples/page_file_dir.git/description +1 -0
  125. data/test/examples/page_file_dir.git/index +0 -0
  126. data/test/examples/page_file_dir.git/info/exclude +6 -0
  127. data/test/examples/page_file_dir.git/logs/HEAD +1 -0
  128. data/test/examples/page_file_dir.git/logs/refs/heads/master +1 -0
  129. data/test/examples/page_file_dir.git/objects/0c/7d27db1f575263efdcab3dc650f4502a2dbcbf +0 -0
  130. data/test/examples/page_file_dir.git/objects/22/b404803c966dd92865614d86ff22ca12e50c1e +0 -0
  131. data/test/examples/page_file_dir.git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99 +0 -0
  132. data/test/examples/page_file_dir.git/objects/57/16ca5987cbf97d6bb54920bea6adde242d87e6 +0 -0
  133. data/test/examples/page_file_dir.git/objects/5b/43e14e0a15fb6f08feab1773d1c0991e9f71e2 +0 -0
  134. data/test/examples/page_file_dir.git/refs/heads/master +1 -0
  135. data/test/examples/revert.git/COMMIT_EDITMSG +1 -0
  136. data/test/examples/revert.git/HEAD +1 -0
  137. data/test/examples/revert.git/config +12 -0
  138. data/test/examples/revert.git/description +1 -0
  139. data/test/examples/revert.git/index +0 -0
  140. data/test/examples/revert.git/info/exclude +6 -0
  141. data/test/examples/revert.git/logs/HEAD +2 -0
  142. data/test/examples/revert.git/logs/refs/heads/master +2 -0
  143. data/test/examples/revert.git/objects/20/2ced67cea93c7b6bd2928aa1daef8d1d55a20d +0 -0
  144. data/test/examples/revert.git/objects/41/76394bfa11222363c66ce7e84b5f154095b6d9 +0 -0
  145. data/test/examples/revert.git/objects/6a/69f92020f5df77af6e8813ff1232493383b708 +0 -0
  146. data/test/examples/revert.git/objects/b4/785957bc986dc39c629de9fac9df46972c00fc +0 -0
  147. data/test/examples/revert.git/objects/f4/03b791119f8232b7cb0ba455c624ac6435f433 +0 -0
  148. data/test/examples/revert.git/objects/info/packs +2 -0
  149. data/test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.idx +0 -0
  150. data/test/examples/revert.git/objects/pack/pack-a561f8437234f74d0bacb9e0eebe52d207f5770d.pack +0 -0
  151. data/test/examples/revert.git/packed-refs +2 -0
  152. data/test/examples/revert.git/refs/heads/master +1 -0
  153. data/test/examples/revert.git/refs/remotes/origin/HEAD +1 -0
  154. data/test/examples/yubiwa.git/HEAD +1 -0
  155. data/test/examples/yubiwa.git/config +5 -0
  156. data/test/examples/yubiwa.git/description +1 -0
  157. data/test/examples/yubiwa.git/info/exclude +6 -0
  158. data/test/examples/yubiwa.git/objects/10/fa2ddc4e3b4009d8a453aace10bd6148c1ad00 +0 -0
  159. data/test/examples/yubiwa.git/objects/52/4b82874327ea7cbf730389964ba7cb3de966de +0 -0
  160. data/test/examples/yubiwa.git/objects/58/3fc201cb457fb3f1480f3e1e5999b119633835 +0 -0
  161. data/test/examples/yubiwa.git/objects/87/bc1dd46ab3d3874d4e898d45dd512cc20a7cc8 +1 -0
  162. data/test/examples/yubiwa.git/objects/89/64ed1b4e21aa90e831763bbce9034bfda81b70 +0 -0
  163. data/test/examples/yubiwa.git/objects/9f/f6dd0660da5fba2d3374adb2b84fa653bb538b +0 -0
  164. data/test/examples/yubiwa.git/objects/ac/e97abf2b177815a1972d7db22f229f58c83309 +0 -0
  165. data/test/examples/yubiwa.git/objects/b1/f443863a4816628807fbf86141ebef055dda34 +0 -0
  166. data/test/examples/yubiwa.git/refs/heads/master +1 -0
  167. data/test/helper.rb +66 -0
  168. data/test/test_app.rb +169 -0
  169. data/test/test_committer.rb +64 -0
  170. data/test/test_file.rb +27 -0
  171. data/test/test_git_access.rb +52 -0
  172. data/test/test_markup.rb +628 -0
  173. data/test/test_page.rb +166 -0
  174. data/test/test_page_revert.rb +45 -0
  175. data/test/test_wiki.rb +462 -0
  176. metadata +470 -0
@@ -0,0 +1,1096 @@
1
+ /**
2
+ * gollum.editor.js
3
+ * A jQuery plugin that creates the Gollum Editor.
4
+ *
5
+ * Usage:
6
+ * $.GollumEditor(); on DOM ready.
7
+ */
8
+ (function($) {
9
+
10
+ // Editor options
11
+ var DefaultOptions = {
12
+ MarkupType: 'markdown',
13
+ EditorMode: 'code',
14
+ NewFile: false,
15
+ HasFunctionBar: true,
16
+ Debug: false,
17
+ NoDefinitionsFor: []
18
+ };
19
+ var ActiveOptions = {};
20
+
21
+ /**
22
+ * $.GollumEditor
23
+ *
24
+ * You don't need to do anything. Just run this on DOM ready.
25
+ */
26
+ $.GollumEditor = function( IncomingOptions ) {
27
+
28
+ ActiveOptions = $.extend( DefaultOptions, IncomingOptions );
29
+
30
+ debug('GollumEditor loading');
31
+
32
+ if ( EditorHas.baseEditorMarkup() ) {
33
+
34
+ if ( EditorHas.titleDisplayed() ) {
35
+ $('#gollum-editor-title-field').addClass('active');
36
+ }
37
+
38
+ if ( EditorHas.editSummaryMarkup() ) {
39
+ $.GollumEditor.Placeholder.add($('#gollum-editor-edit-summary input'));
40
+ $('#gollum-editor form[name="gollum-editor"]').submit(function( e ) {
41
+ e.preventDefault();
42
+ $.GollumEditor.Placeholder.clearAll();
43
+ debug('submitting');
44
+ $(this).unbind('submit');
45
+ $(this).submit();
46
+ });
47
+ }
48
+
49
+ if ( EditorHas.collapsibleInputs() ) {
50
+ $('#gollum-editor .collapsed a.button, ' +
51
+ '#gollum-editor .expanded a.button').click(function( e ) {
52
+ e.preventDefault();
53
+ $(this).parent().toggleClass('expanded');
54
+ $(this).parent().toggleClass('collapsed');
55
+ });
56
+ }
57
+
58
+ if ( EditorHas.previewButton() ) {
59
+ var formAction =
60
+ $('#gollum-editor #gollum-editor-preview').click(function() {
61
+ // make a dummy form, submit to new target window
62
+ // get form fields
63
+ var oldAction = $('#gollum-editor form').attr('action');
64
+ var $form = $($('#gollum-editor form').get(0));
65
+ $form.attr('action', this.href || '/preview');
66
+ $form.attr('target', '_blank');
67
+ $form.submit();
68
+
69
+
70
+ $form.attr('action', oldAction);
71
+ $form.removeAttr('target');
72
+ return false;
73
+ });
74
+ }
75
+
76
+ // Initialize the function bar by loading proper definitions
77
+ if ( EditorHas.functionBar() ) {
78
+
79
+ var htmlSetMarkupLang =
80
+ $('#gollum-editor-body').attr('data-markup-lang');
81
+
82
+ if ( htmlSetMarkupLang ) {
83
+ ActiveOptions.MarkupType = htmlSetMarkupLang;
84
+ }
85
+
86
+ // load language definition
87
+ LanguageDefinition.setActiveLanguage( ActiveOptions.MarkupType );
88
+ if ( EditorHas.formatSelector() ) {
89
+ FormatSelector.init(
90
+ $('#gollum-editor-format-selector select') );
91
+ }
92
+
93
+ if ( EditorHas.help() ) {
94
+ $('#gollum-editor-help').hide();
95
+ $('#gollum-editor-help').removeClass('jaws');
96
+ }
97
+
98
+ }
99
+ // EditorHas.functionBar
100
+ }
101
+ // EditorHas.baseEditorMarkup
102
+ };
103
+
104
+
105
+
106
+ /**
107
+ * $.GollumEditor.defineLanguage
108
+ * Defines a set of language actions that Gollum can use.
109
+ * Used by the definitions in langs/ to register language definitions.
110
+ */
111
+ $.GollumEditor.defineLanguage = function( language_name, languageObject ) {
112
+ if ( typeof languageObject == 'object' ) {
113
+ LanguageDefinition.define( language_name, languageObject );
114
+ } else {
115
+ debug('GollumEditor.defineLanguage: definition for ' + language_name +
116
+ ' is not an object');
117
+ }
118
+ };
119
+
120
+
121
+ /**
122
+ * debug
123
+ * Prints debug information to console.log if debug output is enabled.
124
+ *
125
+ * @param mixed Whatever you want to dump to console.log
126
+ * @return void
127
+ */
128
+ var debug = function(m) {
129
+ if ( ActiveOptions.Debug &&
130
+ typeof console != 'undefined' ) {
131
+ console.log( m );
132
+ }
133
+ };
134
+
135
+
136
+
137
+ /**
138
+ * LanguageDefinition
139
+ * Language definition file handler
140
+ * Loads language definition files as necessary.
141
+ */
142
+ var LanguageDefinition = {
143
+
144
+ _ACTIVE_LANG: '',
145
+ _LOADED_LANGS: [],
146
+ _LANG: {},
147
+
148
+ /**
149
+ * Defines a language
150
+ *
151
+ * @param name string The name of the language
152
+ * @param name object The definition object
153
+ */
154
+ define: function( name, definitionObject ) {
155
+ LanguageDefinition._ACTIVE_LANG = name;
156
+ LanguageDefinition._LOADED_LANGS.push( name );
157
+ if ( typeof $.GollumEditor.WikiLanguage == 'object' ) {
158
+ var definition = {};
159
+ $.extend(definition, $.GollumEditor.WikiLanguage, definitionObject);
160
+ LanguageDefinition._LANG[name] = definition;
161
+ } else {
162
+ LanguageDefinition._LANG[name] = definitionObject;
163
+ }
164
+ },
165
+
166
+ getActiveLanguage: function() {
167
+ return LanguageDefinition._ACTIVE_LANG;
168
+ },
169
+
170
+ setActiveLanguage: function( name ) {
171
+ if(LanguageDefinition.getHookFunctionFor("deactivate")) {
172
+ LanguageDefinition.getHookFunctionFor("deactivate")();
173
+ }
174
+ if ( !LanguageDefinition.isLoadedFor(name) ) {
175
+ LanguageDefinition._ACTIVE_LANG = null;
176
+ LanguageDefinition.loadFor( name, function(x, t) {
177
+ if ( t != 'success' ) {
178
+ debug('Failed to load language definition for ' + name);
179
+ // well, fake it and turn everything off for this one
180
+ LanguageDefinition.define( name, {} );
181
+ }
182
+
183
+ // update features that rely on the language definition
184
+ if ( EditorHas.functionBar() ) {
185
+ FunctionBar.refresh();
186
+ }
187
+
188
+ if ( LanguageDefinition.isValid() && EditorHas.formatSelector() ) {
189
+ FormatSelector.updateSelected();
190
+ }
191
+
192
+ if(LanguageDefinition.getHookFunctionFor("activate")) {
193
+ LanguageDefinition.getHookFunctionFor("activate")();
194
+ }
195
+ } );
196
+ } else {
197
+ LanguageDefinition._ACTIVE_LANG = name;
198
+ FunctionBar.refresh();
199
+
200
+ if(LanguageDefinition.getHookFunctionFor("activate")) {
201
+ LanguageDefinition.getHookFunctionFor("activate")();
202
+ }
203
+ }
204
+ },
205
+
206
+ getHookFunctionFor: function(attr, specified_lang) {
207
+ if ( !specified_lang ) {
208
+ specified_lang = LanguageDefinition._ACTIVE_LANG;
209
+ }
210
+
211
+ if ( LanguageDefinition.isLoadedFor(specified_lang) &&
212
+ LanguageDefinition._LANG[specified_lang][attr] &&
213
+ typeof LanguageDefinition._LANG[specified_lang][attr] == 'function' ) {
214
+ return LanguageDefinition._LANG[specified_lang][attr];
215
+ }
216
+
217
+ return null;
218
+ },
219
+
220
+ /**
221
+ * gets a definition object for a specified attribute
222
+ *
223
+ * @param string attr The specified attribute.
224
+ * @param string specified_lang The language to pull a definition for.
225
+ * @return object if exists, null otherwise
226
+ */
227
+ getDefinitionFor: function( attr, specified_lang ) {
228
+ if ( !specified_lang ) {
229
+ specified_lang = LanguageDefinition._ACTIVE_LANG;
230
+ }
231
+
232
+ if ( LanguageDefinition.isLoadedFor(specified_lang) &&
233
+ LanguageDefinition._LANG[specified_lang][attr] &&
234
+ typeof LanguageDefinition._LANG[specified_lang][attr] == 'object' ) {
235
+ return LanguageDefinition._LANG[specified_lang][attr];
236
+ }
237
+
238
+ return null;
239
+ },
240
+
241
+
242
+ /**
243
+ * loadFor
244
+ * Asynchronously loads a definition file for the current markup.
245
+ * Definition files are necessary to use the code editor.
246
+ *
247
+ * @param string markup_name The markup name you want to load
248
+ * @return void
249
+ */
250
+ loadFor: function( markup_name, on_complete ) {
251
+ // Keep us from hitting 404s on our site, check the definition blacklist
252
+ if ( ActiveOptions.NoDefinitionsFor.length ) {
253
+ for ( var i=0; i < ActiveOptions.NoDefinitionsFor.length; i++ ) {
254
+ if ( markup_name == ActiveOptions.NoDefinitionsFor[i] ) {
255
+ // we don't have this. get out.
256
+ if ( typeof on_complete == 'function' ) {
257
+ on_complete( null, 'error' );
258
+ return;
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ // attempt to load the definition for this language
265
+ var script_uri = '/javascript/editor/langs/' + markup_name + '.js';
266
+ $.ajax({
267
+ url: script_uri,
268
+ dataType: 'script',
269
+ complete: function( xhr, textStatus ) {
270
+ if ( typeof on_complete == 'function' ) {
271
+ on_complete( xhr, textStatus );
272
+ }
273
+ }
274
+ });
275
+ },
276
+
277
+
278
+ /**
279
+ * isLoadedFor
280
+ * Checks to see if a definition file has been loaded for the
281
+ * specified markup language.
282
+ *
283
+ * @param string markup_name The name of the markup.
284
+ * @return boolean
285
+ */
286
+ isLoadedFor: function( markup_name ) {
287
+ if ( LanguageDefinition._LOADED_LANGS.length === 0 ) {
288
+ return false;
289
+ }
290
+
291
+ for ( var i=0; i < LanguageDefinition._LOADED_LANGS.length; i++ ) {
292
+ if ( LanguageDefinition._LOADED_LANGS[i] == markup_name ) {
293
+ return true;
294
+ }
295
+ }
296
+ return false;
297
+ },
298
+
299
+ isValid: function() {
300
+ return ( LanguageDefinition._ACTIVE_LANG &&
301
+ typeof LanguageDefinition._LANG[LanguageDefinition._ACTIVE_LANG] ==
302
+ 'object' );
303
+ }
304
+
305
+ };
306
+
307
+
308
+ /**
309
+ * EditorHas
310
+ * Various conditionals to check what features of the Gollum Editor are
311
+ * active/operational.
312
+ */
313
+ var EditorHas = {
314
+
315
+
316
+ /**
317
+ * EditorHas.baseEditorMarkup
318
+ * True if the basic editor form is in place.
319
+ *
320
+ * @return boolean
321
+ */
322
+ baseEditorMarkup: function() {
323
+ return ( $('#gollum-editor').length &&
324
+ $('#gollum-editor-body').length );
325
+ },
326
+
327
+
328
+ /**
329
+ * EditorHas.collapsibleInputs
330
+ * True if the editor contains collapsible inputs for things like the
331
+ * sidebar or footer, false otherwise.
332
+ *
333
+ * @return boolean
334
+ */
335
+ collapsibleInputs: function() {
336
+ return $('#gollum-editor .collapsed, #gollum-editor .expanded').length;
337
+ },
338
+
339
+
340
+ /**
341
+ * EditorHas.formatSelector
342
+ * True if the editor has a format selector (for switching between
343
+ * language types), false otherwise.
344
+ *
345
+ * @return boolean
346
+ */
347
+ formatSelector: function() {
348
+ return $('#gollum-editor-format-selector select').length;
349
+ },
350
+
351
+
352
+ /**
353
+ * EditorHas.functionBar
354
+ * True if the Function Bar markup exists.
355
+ *
356
+ * @return boolean
357
+ */
358
+ functionBar: function() {
359
+ return ( ActiveOptions.HasFunctionBar &&
360
+ $('#gollum-editor-function-bar').length );
361
+ },
362
+
363
+
364
+ /**
365
+ * EditorHas.ff4Environment
366
+ * True if in a Firefox 4.0 Beta environment.
367
+ *
368
+ * @return boolean
369
+ */
370
+ ff4Environment: function() {
371
+ var ua = new RegExp(/Firefox\/4.0b/);
372
+ return ( ua.test( navigator.userAgent ) );
373
+ },
374
+
375
+
376
+ /**
377
+ * EditorHas.editSummaryMarkup
378
+ * True if the editor has a summary field (Gollum's commit message),
379
+ * false otherwise.
380
+ *
381
+ * @return boolean
382
+ */
383
+ editSummaryMarkup: function() {
384
+ return ( $('input#gollum-editor-message-field').length > 0 );
385
+ },
386
+
387
+
388
+ /**
389
+ * EditorHas.help
390
+ * True if the editor contains the inline help sector, false otherwise.
391
+ *
392
+ * @return boolean
393
+ */
394
+ help: function() {
395
+ return ( $('#gollum-editor #gollum-editor-help').length &&
396
+ $('#gollum-editor #function-help').length );
397
+ },
398
+
399
+
400
+ /**
401
+ * EditorHas.previewButton
402
+ * True if the editor has a preview button, false otherwise.
403
+ *
404
+ * @return boolean
405
+ */
406
+ previewButton: function() {
407
+ return ( $('#gollum-editor #gollum-editor-preview').length );
408
+ },
409
+
410
+
411
+ /**
412
+ * EditorHas.titleDisplayed
413
+ * True if the editor is displaying a title field, false otherwise.
414
+ *
415
+ * @return boolean
416
+ */
417
+ titleDisplayed: function() {
418
+ return ( ActiveOptions.NewFile );
419
+ }
420
+
421
+ };
422
+
423
+
424
+ /**
425
+ * FunctionBar
426
+ *
427
+ * Things the function bar does.
428
+ */
429
+ var FunctionBar = {
430
+
431
+ isActive: false,
432
+
433
+
434
+ /**
435
+ * FunctionBar.activate
436
+ * Activates the function bar, attaching all click events
437
+ * and displaying the bar.
438
+ *
439
+ */
440
+ activate: function() {
441
+ debug('Activating function bar');
442
+
443
+ // check these out
444
+ $('#gollum-editor-function-bar a.function-button').each(function() {
445
+ if ( LanguageDefinition.getDefinitionFor( $(this).attr('id') ) ) {
446
+ $(this).click( FunctionBar.evtFunctionButtonClick );
447
+ $(this).removeClass('disabled');
448
+ }
449
+ else if ( $(this).attr('id') != 'function-help' ) {
450
+ $(this).addClass('disabled');
451
+ }
452
+ });
453
+
454
+ // show bar as active
455
+ $('#gollum-editor-function-bar').addClass( 'active' );
456
+ FunctionBar.isActive = true;
457
+ },
458
+
459
+
460
+ deactivate: function() {
461
+ $('#gollum-editor-function-bar a.function-button').unbind('click');
462
+ $('#gollum-editor-function-bar').removeClass( 'active' );
463
+ FunctionBar.isActive = false;
464
+ },
465
+
466
+
467
+ /**
468
+ * FunctionBar.evtFunctionButtonClick
469
+ * Event handler for the function buttons. Traps the click and
470
+ * executes the proper language action.
471
+ *
472
+ * @param jQuery.Event jQuery event object.
473
+ */
474
+ evtFunctionButtonClick: function(e) {
475
+ e.preventDefault();
476
+ var def = LanguageDefinition.getDefinitionFor( $(this).attr('id') );
477
+ if ( typeof def == 'object' ) {
478
+ FunctionBar.executeAction( def );
479
+ }
480
+ },
481
+
482
+
483
+ /**
484
+ * FunctionBar.executeAction
485
+ * Executes a language-specific defined action for a function button.
486
+ *
487
+ */
488
+ executeAction: function( definitionObject ) {
489
+ // get the selected text from the textarea
490
+ var txt = $('#gollum-editor-body').val();
491
+ // hmm, I'm not sure this will work in a textarea
492
+ var selPos = FunctionBar
493
+ .getFieldSelectionPosition( $('#gollum-editor-body') );
494
+ var selText = FunctionBar.getFieldSelection( $('#gollum-editor-body') );
495
+ var repText = selText;
496
+ var reselect = true;
497
+ var cursor = null;
498
+
499
+ // execute a replacement function if one exists
500
+ if ( definitionObject.exec &&
501
+ typeof definitionObject.exec == 'function' ) {
502
+ definitionObject.exec( txt, selText, $('#gollum-editor-body') );
503
+ return;
504
+ }
505
+
506
+ // execute a search/replace if they exist
507
+ var searchExp = /([^\n]+)/gi;
508
+ if ( definitionObject.search &&
509
+ typeof definitionObject.search == 'object' ) {
510
+ debug('Replacing search Regex');
511
+ searchExp = null;
512
+ searchExp = new RegExp ( definitionObject.search );
513
+ debug( searchExp );
514
+ }
515
+ debug('repText is ' + '"' + repText + '"');
516
+ // replace text
517
+ if ( definitionObject.replace &&
518
+ typeof definitionObject.replace == 'string' ) {
519
+ debug('Running replacement - using ' + definitionObject.replace);
520
+ var rt = definitionObject.replace;
521
+ repText = repText.replace( searchExp, rt );
522
+ // remove backreferences
523
+ repText = repText.replace( /\$[\d]/g, '' );
524
+
525
+ if ( repText === '' ) {
526
+ debug('Search string is empty');
527
+
528
+ // find position of $1 - this is where we will place the cursor
529
+ cursor = rt.indexOf('$1');
530
+
531
+ // we have an empty string, so just remove backreferences
532
+ repText = rt.replace( /\$[\d]/g, '' );
533
+
534
+ // if the position of $1 doesn't exist, stick the cursor in
535
+ // the middle
536
+ if ( cursor == -1 ) {
537
+ cursor = Math.floor( rt.length / 2 );
538
+ }
539
+ }
540
+ }
541
+
542
+ // append if necessary
543
+ if ( definitionObject.append &&
544
+ typeof definitionObject.append == 'string' ) {
545
+ if ( repText == selText ) {
546
+ reselect = false;
547
+ }
548
+ repText += definitionObject.append;
549
+ }
550
+
551
+ if ( repText ) {
552
+ FunctionBar.replaceFieldSelection( $('#gollum-editor-body'),
553
+ repText, reselect, cursor );
554
+ }
555
+
556
+ },
557
+
558
+
559
+ /**
560
+ * getFieldSelectionPosition
561
+ * Retrieves the selection range for the textarea.
562
+ *
563
+ * @return object the .start and .end offsets in the string
564
+ */
565
+ getFieldSelectionPosition: function( $field ) {
566
+ if ($field.length) {
567
+ var start = 0, end = 0;
568
+ var el = $field.get(0);
569
+
570
+ if (typeof el.selectionStart == "number" &&
571
+ typeof el.selectionEnd == "number") {
572
+ start = el.selectionStart;
573
+ end = el.selectionEnd;
574
+ } else {
575
+ var range = document.selection.createRange();
576
+ var stored_range = range.duplicate();
577
+ stored_range.moveToElementText( el );
578
+ stored_range.setEndPoint( 'EndToEnd', range );
579
+ start = stored_range.text.length - range.text.length;
580
+ end = start + range.text.length;
581
+
582
+ // so, uh, we're close, but we need to search for line breaks and
583
+ // adjust the start/end points accordingly since IE counts them as
584
+ // 2 characters in TextRange.
585
+ var s = start;
586
+ var lb = 0;
587
+ var i;
588
+ debug('IE: start position is currently ' + s);
589
+ for ( i=0; i < s; i++ ) {
590
+ if ( el.value.charAt(i).match(/\r/) ) {
591
+ ++lb;
592
+ }
593
+ }
594
+
595
+ if ( lb ) {
596
+ debug('IE start: compensating for ' + lb + ' line breaks');
597
+ start = start - lb;
598
+ lb = 0;
599
+ }
600
+
601
+ var e = end;
602
+ for ( i=0; i < e; i++ ) {
603
+ if ( el.value.charAt(i).match(/\r/) ) {
604
+ ++lb;
605
+ }
606
+ }
607
+
608
+ if ( lb ) {
609
+ debug('IE end: compensating for ' + lb + ' line breaks');
610
+ end = end - lb;
611
+ }
612
+ }
613
+
614
+ return {
615
+ start: start,
616
+ end: end
617
+ };
618
+ } // end if ($field.length)
619
+ },
620
+
621
+
622
+ /**
623
+ * getFieldSelection
624
+ * Returns the currently selected substring of the textarea.
625
+ *
626
+ * @param jQuery A jQuery object for the textarea.
627
+ * @return string Selected string.
628
+ */
629
+ getFieldSelection: function( $field ) {
630
+ var selStr = '';
631
+ var selPos;
632
+
633
+ if ( $field.length ) {
634
+ selPos = FunctionBar.getFieldSelectionPosition( $field );
635
+ selStr = $field.val().substring( selPos.start, selPos.end );
636
+ debug('Selected: ' + selStr + ' (' + selPos.start + ', ' +
637
+ selPos.end + ')');
638
+ return selStr;
639
+ }
640
+ return false;
641
+ },
642
+
643
+
644
+ isShown: function() {
645
+ return ($('#gollum-editor-function-bar').is(':visible'));
646
+ },
647
+
648
+ refresh: function() {
649
+ if ( EditorHas.functionBar() ) {
650
+ debug('Refreshing function bar');
651
+ if ( LanguageDefinition.isValid() ) {
652
+ $('#gollum-editor-function-bar a.function-button').unbind('click');
653
+ FunctionBar.activate();
654
+ if ( Help ) {
655
+ Help.setActiveHelp( LanguageDefinition.getActiveLanguage() );
656
+ }
657
+ } else {
658
+ debug('Language definition is invalid.');
659
+ if ( FunctionBar.isShown() ) {
660
+ // deactivate the function bar; it's not gonna work now
661
+ FunctionBar.deactivate();
662
+ }
663
+ if ( Help.isShown() ) {
664
+ Help.hide();
665
+ }
666
+ }
667
+ }
668
+ },
669
+
670
+
671
+ /**
672
+ * replaceFieldSelection
673
+ * Replaces the currently selected substring of the textarea with
674
+ * a new string.
675
+ *
676
+ * @param jQuery A jQuery object for the textarea.
677
+ * @param string The string to replace the current selection with.
678
+ * @param boolean Reselect the new text range.
679
+ */
680
+ replaceFieldSelection: function( $field, replaceText, reselect, cursorOffset ) {
681
+ var selPos = FunctionBar.getFieldSelectionPosition( $field );
682
+ var fullStr = $field.val();
683
+ var selectNew = true;
684
+ if ( reselect === false) {
685
+ selectNew = false;
686
+ }
687
+
688
+ var scrollTop = null;
689
+ if ( $field[0].scrollTop ) {
690
+ scrollTop = $field[0].scrollTop;
691
+ }
692
+
693
+ $field.val( fullStr.substring(0, selPos.start) + replaceText +
694
+ fullStr.substring(selPos.end) );
695
+ $field[0].focus();
696
+
697
+ if ( selectNew ) {
698
+ if ( $field[0].setSelectionRange ) {
699
+ if ( cursorOffset ) {
700
+ $field[0].setSelectionRange(
701
+ selPos.start + cursorOffset,
702
+ selPos.start + cursorOffset
703
+ );
704
+ } else {
705
+ $field[0].setSelectionRange( selPos.start,
706
+ selPos.start + replaceText.length );
707
+ }
708
+ } else if ( $field[0].createTextRange ) {
709
+ var range = $field[0].createTextRange();
710
+ range.collapse( true );
711
+ if ( cursorOffset ) {
712
+ range.moveEnd( selPos.start + cursorOffset );
713
+ range.moveStart( selPos.start + cursorOffset );
714
+ } else {
715
+ range.moveEnd( 'character', selPos.start + replaceText.length );
716
+ range.moveStart( 'character', selPos.start );
717
+ }
718
+ range.select();
719
+ }
720
+ }
721
+
722
+ if ( scrollTop ) {
723
+ // this jumps sometimes in FF
724
+ $field[0].scrollTop = scrollTop;
725
+ }
726
+ }
727
+ };
728
+
729
+
730
+
731
+ /**
732
+ * FormatSelector
733
+ *
734
+ * Functions relating to the format selector (if it exists)
735
+ */
736
+ var FormatSelector = {
737
+
738
+ $_SELECTOR: null,
739
+
740
+ /**
741
+ * FormatSelector.evtChangeFormat
742
+ * Event handler for when a format has been changed by the format
743
+ * selector. Will automatically load a new language definition
744
+ * via JS if necessary.
745
+ *
746
+ * @return void
747
+ */
748
+ evtChangeFormat: function( e ) {
749
+ var newMarkup = $(this).val();
750
+ LanguageDefinition.setActiveLanguage( newMarkup );
751
+ },
752
+
753
+
754
+ /**
755
+ * FormatSelector.init
756
+ * Initializes the format selector.
757
+ *
758
+ * @return void
759
+ */
760
+ init: function( $sel ) {
761
+ debug('Initializing format selector');
762
+
763
+ // unbind events if init is being called twice for some reason
764
+ if ( FormatSelector.$_SELECTOR &&
765
+ typeof FormatSelector.$_SELECTOR == 'object' ) {
766
+ FormatSelector.$_SELECTOR.unbind( 'change' );
767
+ }
768
+
769
+ FormatSelector.$_SELECTOR = $sel;
770
+
771
+ // set format selector to the current language
772
+ FormatSelector.updateSelected();
773
+ FormatSelector.$_SELECTOR.change( FormatSelector.evtChangeFormat );
774
+ },
775
+
776
+
777
+ /**
778
+ * FormatSelector.update
779
+ */
780
+ updateSelected: function() {
781
+ var currentLang = LanguageDefinition.getActiveLanguage();
782
+ FormatSelector.$_SELECTOR.val( currentLang );
783
+ }
784
+
785
+ };
786
+
787
+
788
+
789
+ /**
790
+ * Help
791
+ *
792
+ * Functions that manage the display and loading of inline help files.
793
+ */
794
+ var Help = {
795
+
796
+ _ACTIVE_HELP: '',
797
+ _LOADED_HELP_LANGS: [],
798
+ _HELP: {},
799
+
800
+ /**
801
+ * Help.define
802
+ *
803
+ * Defines a new help context and enables the help function if it
804
+ * exists in the Gollum Function Bar.
805
+ *
806
+ * @param string name The name you're giving to this help context.
807
+ * Generally, this should match the language name.
808
+ * @param object definitionObject The definition object being loaded from a
809
+ * language / help definition file.
810
+ * @return void
811
+ */
812
+ define: function( name, definitionObject ) {
813
+ if ( Help.isValidHelpFormat( definitionObject ) ) {
814
+ debug('help is a valid format');
815
+
816
+ Help._ACTIVE_HELP_LANG = name;
817
+ Help._LOADED_HELP_LANGS.push( name );
818
+ Help._HELP[name] = definitionObject;
819
+
820
+ if ( $("#function-help").length ) {
821
+ if ( $('#function-help').hasClass('disabled') ) {
822
+ $('#function-help').removeClass('disabled');
823
+ }
824
+ $('#function-help').unbind('click');
825
+ $('#function-help').click( Help.evtHelpButtonClick );
826
+
827
+ // generate help menus
828
+ Help.generateHelpMenuFor( name );
829
+
830
+ if ( $('#gollum-editor-help').length &&
831
+ typeof $('#gollum-editor-help').attr('data-autodisplay') !== 'undefined' &&
832
+ $('#gollum-editor-help').attr('data-autodisplay') === 'true' ) {
833
+ Help.show();
834
+ }
835
+ }
836
+ } else {
837
+ if ( $('#function-help').length ) {
838
+ $('#function-help').addClass('disabled');
839
+ }
840
+ }
841
+ },
842
+
843
+ /**
844
+ * Help.generateHelpMenuFor
845
+ * Generates the markup for the main help menu given a context name.
846
+ *
847
+ * @param string name The context name.
848
+ * @return void
849
+ */
850
+ generateHelpMenuFor: function( name ) {
851
+ if ( !Help._HELP[name] ) {
852
+ debug('Help is not defined for ' + name.toString());
853
+ return false;
854
+ }
855
+ var helpData = Help._HELP[name];
856
+
857
+ // clear this shiz out
858
+ $('#gollum-editor-help-parent').html('');
859
+ $('#gollum-editor-help-list').html('');
860
+ $('#gollum-editor-help-content').html('');
861
+
862
+ // go go inefficient algorithm
863
+ for ( var i=0; i < helpData.length; i++ ) {
864
+ if ( typeof helpData[i] != 'object' ) {
865
+ break;
866
+ }
867
+
868
+ var $newLi = $('<li><a href="#" rel="' + i + '">' +
869
+ helpData[i].menuName + '</a></li>');
870
+ $('#gollum-editor-help-parent').append( $newLi );
871
+ if ( i === 0 ) {
872
+ // select on first run
873
+ $newLi.children('a').addClass('selected');
874
+ }
875
+ $newLi.children('a').click( Help.evtParentMenuClick );
876
+ }
877
+
878
+ // generate parent submenu on first run
879
+ Help.generateSubMenu( helpData[0], 0 );
880
+ $($('#gollum-editor-help-list li a').get(0)).click();
881
+
882
+ },
883
+
884
+ /**
885
+ * Help.generateSubMenu
886
+ * Generates the markup for the inline help sub-menu given the data
887
+ * object for the submenu and the array index to start at.
888
+ *
889
+ * @param object subData The data for the sub-menu.
890
+ * @param integer index The index clicked on (parent menu index).
891
+ * @return void
892
+ */
893
+ generateSubMenu: function( subData, index ) {
894
+ $('#gollum-editor-help-list').html('');
895
+ $('#gollum-editor-help-content').html('');
896
+ for ( var i=0; i < subData.content.length; i++ ) {
897
+ if ( typeof subData.content[i] != 'object' ) {
898
+ break;
899
+ }
900
+
901
+ var $subLi = $('<li><a href="#" rel="' + index + ':' + i + '">' +
902
+ subData.content[i].menuName + '</a></li>');
903
+
904
+
905
+ $('#gollum-editor-help-list').append( $subLi );
906
+ $subLi.children('a').click( Help.evtSubMenuClick );
907
+ }
908
+ },
909
+
910
+ hide: function() {
911
+ if ( $.browser.msie ) {
912
+ $('#gollum-editor-help').css('display', 'none');
913
+ } else {
914
+ $('#gollum-editor-help').animate({
915
+ opacity: 0
916
+ }, 200, function() {
917
+ $('#gollum-editor-help')
918
+ .animate({ height: 'hide' }, 200);
919
+ });
920
+ }
921
+ },
922
+
923
+ show: function() {
924
+ if ( $.browser.msie ) {
925
+ // bypass effects for internet explorer, since it does weird crap
926
+ // to text antialiasing with opacity animations
927
+ $('#gollum-editor-help').css('display', 'block');
928
+ } else {
929
+ $('#gollum-editor-help').animate({
930
+ height: 'show'
931
+ }, 200, function() {
932
+ $('#gollum-editor-help')
933
+ .animate({ opacity: 1 }, 300);
934
+ });
935
+ }
936
+ },
937
+
938
+ /**
939
+ * Help.showHelpFor
940
+ * Displays the actual help content given the two menu indexes, which are
941
+ * rendered in the rel="" attributes of the help menus
942
+ *
943
+ * @param integer index1 parent index
944
+ * @param integer index2 submenu index
945
+ * @return void
946
+ */
947
+ showHelpFor: function( index1, index2 ) {
948
+ var html =
949
+ Help._HELP[Help._ACTIVE_HELP_LANG][index1].content[index2].data;
950
+ $('#gollum-editor-help-content').html(html);
951
+ },
952
+
953
+ /**
954
+ * Help.isLoadedFor
955
+ * Returns true if help is loaded for a specific markup language,
956
+ * false otherwise.
957
+ *
958
+ * @param string name The name of the markup language.
959
+ * @return boolean
960
+ */
961
+ isLoadedFor: function( name ) {
962
+ for ( var i=0; i < Help._LOADED_HELP_LANGS.length; i++ ) {
963
+ if ( name == Help._LOADED_HELP_LANGS[i] ) {
964
+ return true;
965
+ }
966
+ }
967
+ return false;
968
+ },
969
+
970
+ isShown: function() {
971
+ return ($('#gollum-editor-help').is(':visible'));
972
+ },
973
+
974
+ /**
975
+ * Help.isValidHelpFormat
976
+ * Does a quick check to make sure that the help definition isn't in a
977
+ * completely messed-up format.
978
+ *
979
+ * @param object (Array) helpArr The help definition array.
980
+ * @return boolean
981
+ */
982
+ isValidHelpFormat: function( helpArr ) {
983
+ return ( typeof helpArr == 'object' &&
984
+ helpArr.length &&
985
+ typeof helpArr[0].menuName == 'string' &&
986
+ typeof helpArr[0].content == 'object' &&
987
+ helpArr[0].content.length );
988
+ },
989
+
990
+ /**
991
+ * Help.setActiveHelp
992
+ * Sets the active help definition to the one defined in the argument,
993
+ * re-rendering the help menu to match the new definition.
994
+ *
995
+ * @param string name The name of the help definition.
996
+ * @return void
997
+ */
998
+ setActiveHelp: function( name ) {
999
+ if ( !Help.isLoadedFor( name ) ) {
1000
+ if ( $('#function-help').length ) {
1001
+ $('#function-help').addClass('disabled');
1002
+ }
1003
+ if ( Help.isShown() ) {
1004
+ Help.hide();
1005
+ }
1006
+ } else {
1007
+ Help._ACTIVE_HELP_LANG = name;
1008
+ if ( $("#function-help").length ) {
1009
+ if ( $('#function-help').hasClass('disabled') ) {
1010
+ $('#function-help').removeClass('disabled');
1011
+ }
1012
+ $('#function-help').unbind('click');
1013
+ $('#function-help').click( Help.evtHelpButtonClick );
1014
+ Help.generateHelpMenuFor( name );
1015
+ }
1016
+ }
1017
+ },
1018
+
1019
+ /**
1020
+ * Help.evtHelpButtonClick
1021
+ * Event handler for clicking the help button in the function bar.
1022
+ *
1023
+ * @param jQuery.Event e The jQuery event object.
1024
+ * @return void
1025
+ */
1026
+ evtHelpButtonClick: function( e ) {
1027
+ e.preventDefault();
1028
+ if ( Help.isShown() ) {
1029
+ // turn off autodisplay if it's on
1030
+ if ( $('#gollum-editor-help').length &&
1031
+ $('#gollum-editor-help').attr('data-autodisplay') !== 'undefined' &&
1032
+ $('#gollum-editor-help').attr('data-autodisplay') === 'true' ) {
1033
+ $.post('/wiki/help?_method=delete');
1034
+ $('#gollum-editor-help').attr('data-autodisplay', '');
1035
+ }
1036
+ Help.hide(); }
1037
+ else { Help.show(); }
1038
+ },
1039
+
1040
+ /**
1041
+ * Help.evtParentMenuClick
1042
+ * Event handler for clicking on an item in the parent menu. Automatically
1043
+ * renders the submenu for the parent menu as well as the first result for
1044
+ * the actual plain text.
1045
+ *
1046
+ * @param jQuery.Event e The jQuery event object.
1047
+ * @return void
1048
+ */
1049
+ evtParentMenuClick: function( e ) {
1050
+ e.preventDefault();
1051
+ // short circuit if we've selected this already
1052
+ if ( $(this).hasClass('selected') ) { return; }
1053
+
1054
+ // populate from help data for this
1055
+ var helpIndex = $(this).attr('rel');
1056
+ var subData = Help._HELP[Help._ACTIVE_HELP_LANG][helpIndex];
1057
+
1058
+ $('#gollum-editor-help-parent li a').removeClass('selected');
1059
+ $(this).addClass('selected');
1060
+ Help.generateSubMenu( subData, helpIndex );
1061
+ $($('#gollum-editor-help-list li a').get(0)).click();
1062
+ },
1063
+
1064
+ /**
1065
+ * Help.evtSubMenuClick
1066
+ * Event handler for clicking an item in a help submenu. Renders the
1067
+ * appropriate text for the submenu link.
1068
+ *
1069
+ * @param jQuery.Event e The jQuery event object.
1070
+ * @return void
1071
+ */
1072
+ evtSubMenuClick: function( e ) {
1073
+ e.preventDefault();
1074
+ if ( $(this).hasClass('selected') ) { return; }
1075
+
1076
+ // split index rel data
1077
+ var rawIndex = $(this).attr('rel').split(':');
1078
+ $('#gollum-editor-help-list li a').removeClass('selected');
1079
+ $(this).addClass('selected');
1080
+ Help.showHelpFor( rawIndex[0], rawIndex[1] );
1081
+ }
1082
+ };
1083
+
1084
+ // Publicly-accessible function to Help.define
1085
+ $.GollumEditor.defineHelp = Help.define;
1086
+
1087
+ // Dialog exists as its own thing now
1088
+ $.GollumEditor.Dialog = $.GollumDialog;
1089
+ $.GollumEditor.replaceSelection = function( repText ) {
1090
+ FunctionBar.replaceFieldSelection( $('#gollum-editor-body'), repText );
1091
+ };
1092
+
1093
+ // Placeholder exists as its own thing now
1094
+ $.GollumEditor.Placeholder = $.GollumPlaceholder;
1095
+
1096
+ })(jQuery);