radiant-forum-extension 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. data/README.md +155 -0
  2. data/Rakefile +139 -0
  3. data/VERSION +1 -0
  4. data/app/controllers/admin/forums_controller.rb +11 -0
  5. data/app/controllers/forums_controller.rb +34 -0
  6. data/app/controllers/posts_controller.rb +238 -0
  7. data/app/controllers/topics_controller.rb +78 -0
  8. data/app/models/forum.rb +52 -0
  9. data/app/models/moderatorship.rb +5 -0
  10. data/app/models/post.rb +122 -0
  11. data/app/models/post_attachment.rb +73 -0
  12. data/app/models/topic.rb +162 -0
  13. data/app/views/admin/forums/_form.html.haml +25 -0
  14. data/app/views/admin/forums/edit.html.haml +5 -0
  15. data/app/views/admin/forums/index.html.haml +76 -0
  16. data/app/views/admin/forums/moderate.html.haml +2 -0
  17. data/app/views/admin/forums/new.html.haml +5 -0
  18. data/app/views/admin/forums/remove.html.haml +22 -0
  19. data/app/views/admin/pages/_edit_commentability.html.haml +9 -0
  20. data/app/views/admin/reader_settings/_forum.html.haml +4 -0
  21. data/app/views/admin/sites/_choose_forum_layout.html.haml +7 -0
  22. data/app/views/forums/_forum.html.haml +22 -0
  23. data/app/views/forums/index.html.haml +44 -0
  24. data/app/views/forums/show.html.haml +38 -0
  25. data/app/views/forums/show.rss.builder +13 -0
  26. data/app/views/layouts/feed.rss.builder +5 -0
  27. data/app/views/monitorships/create.rjs.erb +1 -0
  28. data/app/views/monitorships/destroy.rjs.erb +1 -0
  29. data/app/views/monitorships/index.html.erb +35 -0
  30. data/app/views/pages/_comment.html.haml +10 -0
  31. data/app/views/pages/_comments.html.haml +15 -0
  32. data/app/views/posts/_attachment.html.haml +2 -0
  33. data/app/views/posts/_form.html.haml +6 -0
  34. data/app/views/posts/_latest.html.haml +17 -0
  35. data/app/views/posts/_post.html.haml +67 -0
  36. data/app/views/posts/_post.rss.builder +13 -0
  37. data/app/views/posts/_reply.html.haml +36 -0
  38. data/app/views/posts/_search.html.haml +28 -0
  39. data/app/views/posts/_uploader.html.haml +16 -0
  40. data/app/views/posts/edit.html.haml +20 -0
  41. data/app/views/posts/index.html.haml +33 -0
  42. data/app/views/posts/index.rss.builder +14 -0
  43. data/app/views/posts/new.html.haml +14 -0
  44. data/app/views/posts/preview.html.haml +32 -0
  45. data/app/views/posts/search.html.haml +54 -0
  46. data/app/views/posts/search.rss.builder +14 -0
  47. data/app/views/posts/show.html.haml +10 -0
  48. data/app/views/reader_notifier/post.rhtml +14 -0
  49. data/app/views/readers/_extra_controls.html.haml +5 -0
  50. data/app/views/readers/show_with_posts.html.haml +47 -0
  51. data/app/views/topics/_form.html.haml +26 -0
  52. data/app/views/topics/_help.html.haml +8 -0
  53. data/app/views/topics/_locked.html.haml +2 -0
  54. data/app/views/topics/_topic.html.haml +35 -0
  55. data/app/views/topics/_topic.rss.builder +9 -0
  56. data/app/views/topics/comments.html.haml +5 -0
  57. data/app/views/topics/edit.html.haml +26 -0
  58. data/app/views/topics/index.html.haml +41 -0
  59. data/app/views/topics/index.rss.builder +14 -0
  60. data/app/views/topics/new.html.haml +40 -0
  61. data/app/views/topics/show.html.haml +45 -0
  62. data/app/views/topics/show.rss.builder +14 -0
  63. data/config/routes.rb +16 -0
  64. data/db/migrate/001_create_forum_tables.rb +64 -0
  65. data/db/migrate/002_pages_commentable.rb +16 -0
  66. data/db/migrate/003_extend_sites.rb +13 -0
  67. data/db/migrate/004_sample_layout.rb +41 -0
  68. data/db/migrate/005_post_attachments.rb +19 -0
  69. data/db/migrate/006_user_relations.rb +20 -0
  70. data/db/migrate/007_reader_ownership.rb +35 -0
  71. data/db/migrate/008_first_posts.rb +13 -0
  72. data/db/migrate/20090824111005_import_helpers.rb +15 -0
  73. data/forum_extension.rb +44 -0
  74. data/lib/forum_admin_ui.rb +37 -0
  75. data/lib/forum_helper.rb +109 -0
  76. data/lib/forum_page.rb +45 -0
  77. data/lib/forum_reader.rb +9 -0
  78. data/lib/forum_reader_notifier.rb +9 -0
  79. data/lib/forum_readers_controller.rb +15 -0
  80. data/lib/forum_red_cloth3.rb +10 -0
  81. data/lib/forum_red_cloth4.rb +21 -0
  82. data/lib/forum_site.rb +12 -0
  83. data/lib/forum_tags.rb +285 -0
  84. data/lib/tasks/radiant_forum_extension_tasks.rake +137 -0
  85. data/pkg/radiant-forum-extension-0.5.0.gem +0 -0
  86. data/public/images/admin/forum.png +0 -0
  87. data/public/images/admin/new-forum.png +0 -0
  88. data/public/images/admin/nominus.png +0 -0
  89. data/public/images/admin/noremove.png +0 -0
  90. data/public/images/emoticons/angry.gif +0 -0
  91. data/public/images/emoticons/bigsmile.gif +0 -0
  92. data/public/images/emoticons/confused.gif +0 -0
  93. data/public/images/emoticons/cool.gif +0 -0
  94. data/public/images/emoticons/cry.gif +0 -0
  95. data/public/images/emoticons/devil.gif +0 -0
  96. data/public/images/emoticons/neutral.gif +0 -0
  97. data/public/images/emoticons/sad.gif +0 -0
  98. data/public/images/emoticons/shamed.gif +0 -0
  99. data/public/images/emoticons/shocked.gif +0 -0
  100. data/public/images/emoticons/smile.gif +0 -0
  101. data/public/images/emoticons/surprised.gif +0 -0
  102. data/public/images/emoticons/tongue.gif +0 -0
  103. data/public/images/emoticons/wink.gif +0 -0
  104. data/public/images/forum/attachment.png +0 -0
  105. data/public/images/forum/attachment_link.png +0 -0
  106. data/public/images/forum/attachment_over.png +0 -0
  107. data/public/images/forum/chk_off.png +0 -0
  108. data/public/images/forum/chk_on.png +0 -0
  109. data/public/images/forum/feed_14.png +0 -0
  110. data/public/images/forum/feed_28.png +0 -0
  111. data/public/images/forum/post_14.png +0 -0
  112. data/public/images/forum/post_14_over.png +0 -0
  113. data/public/images/forum/rdo_off.png +0 -0
  114. data/public/images/forum/rdo_on.png +0 -0
  115. data/public/images/forum/wait_16_grey.gif +0 -0
  116. data/public/javascripts/platform/forum.js +175 -0
  117. data/public/javascripts/platform/remotecontent.js +89 -0
  118. data/public/stylesheets/admin/forum.css +87 -0
  119. data/public/stylesheets/platform/forum.css +70 -0
  120. data/radiant-forum-extension.gemspec +215 -0
  121. data/spec/controllers/admin/forums_controller_spec.rb +54 -0
  122. data/spec/controllers/forums_controller_spec.rb +42 -0
  123. data/spec/controllers/posts_controller_spec.rb +310 -0
  124. data/spec/controllers/topics_controller_spec.rb +133 -0
  125. data/spec/datasets/forum_layouts_dataset.rb +15 -0
  126. data/spec/datasets/forum_pages_dataset.rb +11 -0
  127. data/spec/datasets/forum_readers_dataset.rb +55 -0
  128. data/spec/datasets/forum_sites_dataset.rb +10 -0
  129. data/spec/datasets/forums_dataset.rb +28 -0
  130. data/spec/datasets/posts_dataset.rb +31 -0
  131. data/spec/datasets/topics_dataset.rb +37 -0
  132. data/spec/lib/forum_admin_ui_spec.rb +35 -0
  133. data/spec/lib/forum_page_spec.rb +63 -0
  134. data/spec/lib/forum_reader_notification_spec.rb +9 -0
  135. data/spec/lib/forum_reader_spec.rb +13 -0
  136. data/spec/lib/forum_site_spec.rb +39 -0
  137. data/spec/models/forum_spec.rb +48 -0
  138. data/spec/models/post_spec.rb +91 -0
  139. data/spec/models/topic_spec.rb +105 -0
  140. data/spec/spec.opts +6 -0
  141. data/spec/spec_helper.rb +44 -0
  142. data/vendor/plugins/acts_as_list/README +23 -0
  143. data/vendor/plugins/acts_as_list/init.rb +3 -0
  144. data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
  145. data/vendor/plugins/acts_as_list/test/list_test.rb +332 -0
  146. metadata +287 -0
@@ -0,0 +1,137 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :forum do
4
+
5
+ desc "Runs the migration of the Forum extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ ForumExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ ForumExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ desc "Copies public assets of the Forum to the instance public/ directory."
16
+ task :update => :environment do
17
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
18
+ Dir[ForumExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
19
+ path = file.sub(ForumExtension.root, '')
20
+ directory = File.dirname(path)
21
+ puts "Copying #{path}..."
22
+ mkdir_p RAILS_ROOT + directory
23
+ cp file, RAILS_ROOT + path
24
+ end
25
+ end
26
+
27
+ namespace :import do
28
+ desc "Quick and dirty import from Vanilla."
29
+ task :vanilla => :environment do
30
+ require 'dbi'
31
+
32
+ database = ENV['database'] || 'vanilla'
33
+ user = ENV['user'] || 'forum'
34
+ password = ENV['password'] || ''
35
+ Page.current_site = Site.find_by_id(ENV['site']) if ENV['site'] && defined? Site
36
+
37
+ dbh = DBI.connect("DBI:Mysql:#{database}", user, password)
38
+
39
+ dbh.select_all('select * from LUM_User') do | row |
40
+ begin
41
+ reader = Reader.find_or_create_by_email(row['Email'])
42
+ if reader.new_record?
43
+ reader_name = [row['FirstName'], row['LastName']].join(' ')
44
+ reader_name = row['Name'] if reader_name == ' '
45
+ reader.update_attributes(
46
+ :old_id => row['UserID'],
47
+ :name => reader_name,
48
+ :login => row['Name'],
49
+ :last_login_ip => row['RemoteIp'],
50
+ :last_request_at => row['DateLastActive'],
51
+ :password => 'import',
52
+ :password_confirmation => 'import'
53
+ )
54
+ p "Imported reader #{reader.name} (#{reader.old_id})"
55
+ reader.crypted_password = row['Password']
56
+ reader.save!
57
+ else
58
+ reader.update_attribute( :old_id, row['UserID'] )
59
+ end
60
+ rescue ActiveRecord::RecordInvalid => e
61
+ p "!!! failed to import person #{row['UserID']}: #{e.inspect}"
62
+ end
63
+ end
64
+
65
+ p "*** importing forums"
66
+
67
+ dbh.select_all('select * from LUM_Category') do | row |
68
+ forum = Forum.find_or_create_by_old_id(row['CategoryID'])
69
+ if forum.new_record?
70
+ forum.update_attributes(
71
+ :name => row['Name'],
72
+ :description => row['Description'],
73
+ :position => row['Priority']
74
+ )
75
+ p "Imported forum #{forum.name}"
76
+ end
77
+ end
78
+
79
+ posts = {}
80
+ topic_posts = {}
81
+ dbh.select_all('select * from LUM_Comment ORDER BY DateCreated ASC') do | row |
82
+ posts[row['CommentID']] = row
83
+ topic_posts[row['DiscussionID']] ||= []
84
+ topic_posts[row['DiscussionID']].push(row)
85
+ end
86
+
87
+ p "*** importing topics"
88
+
89
+ dbh.select_all('select * from LUM_Discussion') do | row |
90
+ first_post = posts[row['FirstCommentID']] || topic_posts[row['DiscussionID']].shift
91
+ forum = Forum.find_by_old_id(row['CategoryID'])
92
+ raise "no forum for old id #{row['CategoryID']}. Go fix." unless forum
93
+ if forum && first_post
94
+ topic = forum.topics.build(
95
+ :reader => Reader.find_by_old_id(row['AuthUserID']),
96
+ :name => row['Name'],
97
+ :body => first_post['Body'],
98
+ :created_at => row['DateCreated'],
99
+ :replied_at => topic_posts[row['DiscussionID']].last['DateCreated'],
100
+ :sticky => row['Sticky'],
101
+ :locked => row['Closed'],
102
+ :replied_by => Reader.find_by_old_id(row['LastUserID']),
103
+ :old_id => row['DiscussionID']
104
+ )
105
+
106
+ begin
107
+ if topic.save!
108
+ p "Imported topic #{topic.name}"
109
+
110
+ topic_posts[row['DiscussionID']].each do |post|
111
+ unless post['CommentID'] == row['FirstCommentID'] # first post is created in a pre-validation filter, so we can't check for its old_id
112
+ post = topic.posts.build(
113
+ :forum => forum,
114
+ :reader => Reader.find_by_old_id(post['AuthUserID']),
115
+ :created_at => post['DateCreated'],
116
+ :updated_at => post['DateEdited'],
117
+ :body => post['Body'],
118
+ :old_id => post['CommentID']
119
+ )
120
+ post.save
121
+ end
122
+ end
123
+ p "... with #{topic.posts.count} post" + (topic.posts.count == 1 ? '' : 's')
124
+ end
125
+ rescue ActiveRecord::RecordInvalid => e
126
+ p "!!! failed to import topic #{row['DiscussionID']}: #{e.inspect}"
127
+ end
128
+
129
+ else
130
+ p "skipping topic #{row['Name']}: no post"
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,175 @@
1
+ var Post = new Class({
2
+ initialize: function (div) {
3
+ this.container = div;
4
+ this.header = div.getElement('div.post_header');
5
+ this.wrapper = div.getElement('div.post_wrapper');
6
+ this.body_holder = div.getElement('div.post_body');
7
+ this.h = this.body_holder.getHeight();
8
+ this.editors = this.container.getElements('a.edit_post');
9
+ this.editors.each(function (a) {
10
+ a.addEvent('click', this.edit.bindWithEvent(this));
11
+ }, this);
12
+ this.showing = false;
13
+ this.form_holder = null;
14
+ this.form = null;
15
+ },
16
+
17
+ edit: function(e){
18
+ unevent(e);
19
+ var link = e.target;
20
+ link.addClass('waiting');
21
+ if (this.showing) this.cancel();
22
+ else if (this.form_holder) this.prepForm();
23
+ else this.getForm(link.get('href'));
24
+ },
25
+
26
+ getForm: function (url) {
27
+ if (url) this.formHolder().load(url);
28
+ },
29
+
30
+ formHolder: function () {
31
+ if (this.form_holder) return this.form_holder;
32
+ this.form_holder = new Element('div', {'class': 'post_form'});
33
+ this.form_holder.set('load', {onComplete: this.prepForm.bind(this)});
34
+ return this.form_holder;
35
+ },
36
+
37
+ prepForm: function () {
38
+ this.form_holder.inject(this.wrapper, 'top');
39
+ this.body_holder.hide();
40
+ this.editors.removeClass('waiting');
41
+ this.form = this.form_holder.getElement('form');
42
+ this.input = this.form.getElement('textarea');
43
+ this.input.setStyle('height', this.h);
44
+ this.form_holder.getElement('a.cancel').addEvent('click', this.cancel.bindWithEvent(this));
45
+ this.uploader = new UploadHandler(this.form_holder.getElement('div.upload_handler'));
46
+ this.stumbit = this.form_holder.getElement('div.buttons');
47
+ this.form.onsubmit = this.sendForm.bind(this);
48
+ // new Fx.Morph(this.input, {duration: 'short'}).start({'height' : 240, opacity : 1});
49
+ this.form_holder.show();
50
+ this.showing = true;
51
+ },
52
+
53
+ sendForm: function (e) {
54
+ var waiter = new Element('p', {'class' : 'waiting'}).set('text', 'please wait');
55
+ waiter.replaces(this.stumbit);
56
+
57
+ if (this.uploader && this.uploader.hasUploads()) {
58
+ // can't send uploads over xmlhttp so we allow the form to submit
59
+ // the update-post action will redirect to a hashed url that should return us to the right post
60
+ } else {
61
+ unevent(e);
62
+ new Request.HTML({
63
+ url: this.form.get('action'),
64
+ update: this.container,
65
+ onComplete: this.finishEdit.bind(this)
66
+ }).post(this.form);
67
+ }
68
+
69
+ },
70
+ cancel: function (e) {
71
+ unevent(e);
72
+ this.finishCancel();
73
+ // new Fx.Morph(this.input, {duration: 'short', onComplete : this.finishCancel.bind(this)}).start({'height' : this.h, opacity : 0});
74
+ },
75
+ finishCancel: function () {
76
+ this.form_holder.hide();
77
+ this.body_holder.show();
78
+ this.editors.removeClass('waiting');
79
+ this.showing = false;
80
+ },
81
+ finishEdit: function () {
82
+ this.container.highlight();
83
+ new Post(this.container);
84
+ }
85
+ });
86
+
87
+ var uh = null;
88
+ var UploadHandler = new Class({
89
+ initialize: function (div) {
90
+ this.container = div;
91
+ this.shower = div.getElement('a');
92
+ this.list = div.getElement('ul.attachments');
93
+ this.pender = div.getElement('div.uploads');
94
+ this.selector = div.getElement('div.selector');
95
+ this.file_field_template = this.selector.getElement('input').clone();
96
+ this.file_pending_template = new Element('li');
97
+
98
+ this.attachments = [];
99
+ this.list.getElements('li.attachment').each(function (li) { this.attachments.push( new Attachment(li)); }, this);
100
+
101
+ this.uploads = [];
102
+ this.uploader = this.selector.getElement('input');
103
+ this.uploader.addEvent('change', this.addUpload.bindWithEvent(this));
104
+ this.fakelink = this.selector.getElement('a');
105
+
106
+ // this.reveal.hide();
107
+ uh = this;
108
+ },
109
+ addUpload: function (e) {
110
+ unevent(e);
111
+ this.uploads.push(new Upload(this));
112
+ this.fakelink.set('text', 'attach another file');
113
+ },
114
+ pendUpload: function (argument) {
115
+ var ul = this.uploader.inject(this.pender);
116
+ this.uploader = ul.clone().inject(this.selector);
117
+ this.uploader.set('value', null);
118
+ this.uploader.addEvent('change', this.addUpload.bindWithEvent(this));
119
+ return ul;
120
+ },
121
+ hasAttachments: function () {
122
+ return this.attachments.length > 0;
123
+ },
124
+ hasUploads: function () {
125
+ return this.uploads.length > 0;
126
+ }
127
+ });
128
+
129
+ var Upload = new Class({
130
+ initialize: function (handler) {
131
+ this.handler = handler;
132
+ this.uploader = this.handler.pendUpload();
133
+ this.container = new Element('li', {'class': 'attachment'}).set('text', ' ' + this.uploader.value + ' ');
134
+ this.icon = new Element('img').set('src', this.icon_for(this.uploader.value)).inject(this.container, 'top');
135
+ this.remover = new Element('a', {'class': 'remove', 'href': '#'}).set('text', 'remove').inject(this.container, 'bottom');
136
+ this.remover.addEvent('click', this.remove.bindWithEvent(this));
137
+ this.container.inject(this.handler.list, 'bottom');
138
+ this.container.set('morph', {duration : 'long'});
139
+ this.container.reveal();
140
+ },
141
+ icon_for: function (filename) {
142
+ return '/images/forum/attachment.png';
143
+ },
144
+ remove: function (e) {
145
+ unevent(e);
146
+ this.uploader.destroy();
147
+ this.container.nix();
148
+ }
149
+ });
150
+
151
+ var Attachment = new Class({
152
+ initialize: function (li) {
153
+ this.container = li;
154
+ this.checkbox = li.getElement('input.choose_attachment');
155
+ this.remover = li.getElement('a.remove');
156
+ this.remover.addEvent('click', this.remove.bindWithEvent(this));
157
+ },
158
+ remove: function (e) {
159
+ unevent(e);
160
+ if (this.checkbox) this.checkbox.set('checked', false);
161
+ this.container.nix();
162
+ },
163
+ hide: function () {
164
+ this.container.hide();
165
+ }
166
+ });
167
+
168
+
169
+
170
+
171
+
172
+ activations.push(function (scope) {
173
+ scope.getElements('div.post').each(function (div) { new Post(div); });
174
+ scope.getElements('div.upload_handler').each(function (div) { new UploadHandler(div); });
175
+ });
@@ -0,0 +1,89 @@
1
+ // self-replacing links
2
+ // puts the get results in place of the link.
3
+
4
+ var InlineLink = new Class({
5
+ initialize: function (a) {
6
+ this.link = a;
7
+ this.link.onclick = this.sendLink.bindWithEvent(this);
8
+ this.catcher = new Element('div', {'class' : 'remote_content'}).wraps(this.link);
9
+ this.catcher.set('load', {
10
+ onRequest: this.waiting.bind(this),
11
+ onSuccess: this.finish.bind(this),
12
+ onFailure: this.fail.bind(this)
13
+ });
14
+ },
15
+ sendLink: function (e) {
16
+ unevent(e);
17
+ this.link.blur();
18
+ this.catcher.load(this.link.get('href'));
19
+ },
20
+ finish: function (response) {
21
+ activate(this.catcher);
22
+ this.catcher.highlight('#f27877');
23
+ activate(this.catcher);
24
+ },
25
+ fail: function (response) {
26
+ this.notWaiting();
27
+ this.catcher.addClass('failed');
28
+ },
29
+ waiting: function () {
30
+ this.link.addClass('waiting');
31
+ },
32
+ notWaiting: function () {
33
+ this.link.removeClass('waiting');
34
+ }
35
+ });
36
+
37
+ // self-replacing forms
38
+ // puts the post results in place of the form.
39
+
40
+ var InlineForm = new Class ({
41
+ initialize: function (form) {
42
+ this.form = form;
43
+ var catchers = this.form.getParents().filter(function (parent) { return parent.hasClass('remote_content'); });
44
+ this.catcher = catchers[0] || new Element('div', {'class' : 'remote_content'}).wraps(this.form);
45
+ this.catcher.set('load', {
46
+ url: this.form.get('action'),
47
+ onRequest: this.waiting.bind(this),
48
+ onSuccess: this.finish.bind(this),
49
+ onFailure: this.fail.bind(this)
50
+ });
51
+ this.form.onsubmit = this.sendForm.bindWithEvent(this);
52
+ },
53
+
54
+ sendForm: function (e) {
55
+ unevent(e);
56
+ this.catcher.get('load').post(this.form);
57
+ },
58
+
59
+ finish: function (response) {
60
+ activate(this.catcher);
61
+ this.catcher.highlight('#f27877');
62
+ activate(this.catcher);
63
+ },
64
+
65
+ fail: function (argument) {
66
+ this.notWaiting();
67
+ this.catcher.addClass('failed');
68
+ },
69
+
70
+ waiting: function () {
71
+ this.form.getElements('input').each(function (input) { input.disabled = true; });
72
+ this.form.getElement('p.buttons').addClass('waiting');
73
+ },
74
+
75
+ notWaiting: function () {
76
+ this.form.getElements('input').each(function (input) { input.disabled = false; });
77
+ this.form.getElement('p.buttons').removeClass('waiting');
78
+ }
79
+ });
80
+
81
+
82
+
83
+
84
+
85
+ activations.push(function (scope) {
86
+ scope.getElements('a.inline').each(function (a) { new InlineLink(a); });
87
+ scope.getElements('a.remote_content').each(function (a) { new InlineLink(a).sendLink(); });
88
+ scope.getElements('form.inline').each(function (form) { new InlineForm(form); });
89
+ });