jschat 0.1.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.
Files changed (92) hide show
  1. data/MIT-LICENSE +23 -0
  2. data/README.textile +71 -0
  3. data/bin/jschat-client +3 -0
  4. data/bin/jschat-server +18 -0
  5. data/bin/jschat-web +7 -0
  6. data/lib/jschat/client.rb +745 -0
  7. data/lib/jschat/errors.rb +41 -0
  8. data/lib/jschat/flood_protection.rb +39 -0
  9. data/lib/jschat/http/config/sprockets.yml +7 -0
  10. data/lib/jschat/http/config.ru +12 -0
  11. data/lib/jschat/http/jschat.rb +264 -0
  12. data/lib/jschat/http/public/favicon.ico +0 -0
  13. data/lib/jschat/http/public/images/emoticons/angry.gif +0 -0
  14. data/lib/jschat/http/public/images/emoticons/arr.gif +0 -0
  15. data/lib/jschat/http/public/images/emoticons/blink.gif +0 -0
  16. data/lib/jschat/http/public/images/emoticons/blush.gif +0 -0
  17. data/lib/jschat/http/public/images/emoticons/brucelee.gif +0 -0
  18. data/lib/jschat/http/public/images/emoticons/btw.gif +0 -0
  19. data/lib/jschat/http/public/images/emoticons/chuckle.gif +0 -0
  20. data/lib/jschat/http/public/images/emoticons/clap.gif +0 -0
  21. data/lib/jschat/http/public/images/emoticons/cool.gif +0 -0
  22. data/lib/jschat/http/public/images/emoticons/drool.gif +0 -0
  23. data/lib/jschat/http/public/images/emoticons/drunk.gif +0 -0
  24. data/lib/jschat/http/public/images/emoticons/dry.gif +0 -0
  25. data/lib/jschat/http/public/images/emoticons/eek.gif +0 -0
  26. data/lib/jschat/http/public/images/emoticons/flex.gif +0 -0
  27. data/lib/jschat/http/public/images/emoticons/happy.gif +0 -0
  28. data/lib/jschat/http/public/images/emoticons/holmes.gif +0 -0
  29. data/lib/jschat/http/public/images/emoticons/huh.gif +0 -0
  30. data/lib/jschat/http/public/images/emoticons/laugh.gif +0 -0
  31. data/lib/jschat/http/public/images/emoticons/lol.gif +0 -0
  32. data/lib/jschat/http/public/images/emoticons/mad.gif +0 -0
  33. data/lib/jschat/http/public/images/emoticons/mellow.gif +0 -0
  34. data/lib/jschat/http/public/images/emoticons/noclue.gif +0 -0
  35. data/lib/jschat/http/public/images/emoticons/oh.gif +0 -0
  36. data/lib/jschat/http/public/images/emoticons/ohmy.gif +0 -0
  37. data/lib/jschat/http/public/images/emoticons/ph34r.gif +0 -0
  38. data/lib/jschat/http/public/images/emoticons/pimp.gif +0 -0
  39. data/lib/jschat/http/public/images/emoticons/punch.gif +0 -0
  40. data/lib/jschat/http/public/images/emoticons/realmad.gif +0 -0
  41. data/lib/jschat/http/public/images/emoticons/rock.gif +0 -0
  42. data/lib/jschat/http/public/images/emoticons/rofl.gif +0 -0
  43. data/lib/jschat/http/public/images/emoticons/rolleyes.gif +0 -0
  44. data/lib/jschat/http/public/images/emoticons/sad.gif +0 -0
  45. data/lib/jschat/http/public/images/emoticons/scratch.gif +0 -0
  46. data/lib/jschat/http/public/images/emoticons/shifty.gif +0 -0
  47. data/lib/jschat/http/public/images/emoticons/shock.gif +0 -0
  48. data/lib/jschat/http/public/images/emoticons/shrug.gif +0 -0
  49. data/lib/jschat/http/public/images/emoticons/sleep.gif +0 -0
  50. data/lib/jschat/http/public/images/emoticons/sleeping.gif +0 -0
  51. data/lib/jschat/http/public/images/emoticons/smile.gif +0 -0
  52. data/lib/jschat/http/public/images/emoticons/suicide.gif +0 -0
  53. data/lib/jschat/http/public/images/emoticons/sweat.gif +0 -0
  54. data/lib/jschat/http/public/images/emoticons/thumbs.gif +0 -0
  55. data/lib/jschat/http/public/images/emoticons/tongue.gif +0 -0
  56. data/lib/jschat/http/public/images/emoticons/unsure.gif +0 -0
  57. data/lib/jschat/http/public/images/emoticons/w00t.gif +0 -0
  58. data/lib/jschat/http/public/images/emoticons/wacko.gif +0 -0
  59. data/lib/jschat/http/public/images/emoticons/whistling.gif +0 -0
  60. data/lib/jschat/http/public/images/emoticons/wink.gif +0 -0
  61. data/lib/jschat/http/public/images/emoticons/worship.gif +0 -0
  62. data/lib/jschat/http/public/images/emoticons/yucky.gif +0 -0
  63. data/lib/jschat/http/public/images/jschat.gif +0 -0
  64. data/lib/jschat/http/public/images/shadow.png +0 -0
  65. data/lib/jschat/http/public/javascripts/app/controllers/chat_controller.js +191 -0
  66. data/lib/jschat/http/public/javascripts/app/controllers/signon_controller.js +56 -0
  67. data/lib/jschat/http/public/javascripts/app/helpers/emote_helper.js +23 -0
  68. data/lib/jschat/http/public/javascripts/app/helpers/form_helpers.js +37 -0
  69. data/lib/jschat/http/public/javascripts/app/helpers/link_helper.js +47 -0
  70. data/lib/jschat/http/public/javascripts/app/helpers/page_helper.js +27 -0
  71. data/lib/jschat/http/public/javascripts/app/helpers/text_helper.js +92 -0
  72. data/lib/jschat/http/public/javascripts/app/lib/split.js +78 -0
  73. data/lib/jschat/http/public/javascripts/app/models/cookie.js +27 -0
  74. data/lib/jschat/http/public/javascripts/app/protocol/change.js +15 -0
  75. data/lib/jschat/http/public/javascripts/app/protocol/chat_request.js +13 -0
  76. data/lib/jschat/http/public/javascripts/app/protocol/display.js +147 -0
  77. data/lib/jschat/http/public/javascripts/app/ui/commands.js +55 -0
  78. data/lib/jschat/http/public/javascripts/app/ui/tab_completion.js +122 -0
  79. data/lib/jschat/http/public/javascripts/init.js +19 -0
  80. data/lib/jschat/http/public/stylesheets/iphone.css +3 -0
  81. data/lib/jschat/http/public/stylesheets/screen.css +68 -0
  82. data/lib/jschat/http/script/sprockets.rb +14 -0
  83. data/lib/jschat/http/tmp/restart.txt +0 -0
  84. data/lib/jschat/http/views/index.erb +23 -0
  85. data/lib/jschat/http/views/iphone.erb +29 -0
  86. data/lib/jschat/http/views/layout.erb +29 -0
  87. data/lib/jschat/http/views/message_form.erb +15 -0
  88. data/lib/jschat/server.rb +503 -0
  89. data/test/server_test.rb +175 -0
  90. data/test/stateless_test.rb +33 -0
  91. data/test/test_helper.rb +61 -0
  92. metadata +223 -0
@@ -0,0 +1,147 @@
1
+ var Display = {
2
+ scrolled: false,
3
+
4
+ add_message: function(text, className, time) {
5
+ var time_html = '<span class="time">\#{time}</span>'.interpolate({ time: TextHelper.dateText(time) });
6
+ $('messages').insert({ bottom: '<li class="' + className + '">' + time_html + ' ' + text + '</li>' });
7
+ this.scrollMessagesToTop();
8
+ },
9
+
10
+ addImageOnLoads: function() {
11
+ $$('#messages li').last().select('img').each(function(element) {
12
+ element.observe('load', this.scrollMessagesToTop);
13
+ }.bind(this));
14
+ },
15
+
16
+ message: function(message) {
17
+ var name = $('name').innerHTML;
18
+ var user_class = name == message['user'] ? 'user active' : 'user';
19
+ var text = '<span class="\#{user_class}">\#{user}</span> <span class="\#{message_class}">\#{message}</span>';
20
+
21
+ if (message['message'].match(new RegExp(name, 'i')) && name != message['user']) {
22
+ user_class = 'user mentioned';
23
+ }
24
+
25
+ Display.clearIdleState(message['user']);
26
+
27
+ text = text.interpolate({ user_class: user_class, room: message['room'], user: TextHelper.truncateName(message['user']), message: TextHelper.decorateMessage(message['message']), message_class: 'message' });
28
+ this.add_message(text, 'message', message['time']);
29
+
30
+ this.addImageOnLoads();
31
+
32
+ if (this.show_unread) {
33
+ this.unread++;
34
+ document.title = 'JsChat: (' + this.unread + ') new messages';
35
+ }
36
+ },
37
+
38
+ messages: function(messages) {
39
+ $('messages').innerHTML = '';
40
+ this.ignore_notices = true;
41
+
42
+ $A(messages).each(function(json) {
43
+ try {
44
+ if (json['change']) {
45
+ Change[json['change']](json[json['change']]);
46
+ } else {
47
+ this[json['display']](json[json['display']]);
48
+ }
49
+ } catch (exception) {
50
+ }
51
+ }.bind(this));
52
+
53
+ this.ignore_notices = false;
54
+ this.scrollMessagesToTop();
55
+ /* This is assumed to be the point at which displaying /lastlog completes */
56
+ $('loading').hide();
57
+ Cookie.create('jschat-name', $('name').innerHTML, 28, '/');
58
+ },
59
+
60
+ scrollMessagesToTop: function() {
61
+ if (!this.scrolled) {
62
+ $('messages').scrollTop = $('messages').scrollHeight;
63
+ }
64
+ },
65
+
66
+ clearIdleState: function(user_name) {
67
+ $$('#names li').each(function(element) {
68
+ if (element.innerHTML == user_name && element.hasClassName('idle')) {
69
+ element.lastIdle = (new Date());
70
+ element.removeClassName('idle');
71
+ }
72
+ });
73
+ },
74
+
75
+ isIdle: function(dateValue) {
76
+ try {
77
+ var d = typeof dateValue == 'string' ? new Date(Date.parse(dateValue)) : dateValue,
78
+ now = new Date();
79
+ if (((now - d) / 1000) > (60 * 5)) {
80
+ return true;
81
+ }
82
+ } catch (exception) {
83
+ console.log(exception);
84
+ }
85
+ return false;
86
+ },
87
+
88
+ names: function(users) {
89
+ $('names').innerHTML = '';
90
+ users.each(function(user) {
91
+ var name = user['name'],
92
+ list_class = this.isIdle(user['last_activity']) ? 'idle' : '',
93
+ element = $(document.createElement('li'));
94
+
95
+ element.addClassName(list_class);
96
+ element.innerHTML = TextHelper.truncateName(name);
97
+ $('names').insert({ bottom: element });
98
+
99
+ try {
100
+ // Record the last idle time so the idle state can be dynamically updated
101
+ element.lastIdle = new Date(Date.parse(user['last_activity']));
102
+ } catch (exception) {
103
+ element.lastIdle = null;
104
+ }
105
+ }.bind(this));
106
+ },
107
+
108
+ join: function(join) {
109
+ $('room-name').innerHTML = TextHelper.truncateRoomName(join['room']);
110
+ $('room-name').title = PageHelper.currentRoom();
111
+ },
112
+
113
+ join_notice: function(join) {
114
+ this.add_user(join['user']);
115
+ this.add_message(join['user'] + ' has joined the room', 'server', join['time']);
116
+ },
117
+
118
+ add_user: function(name) {
119
+ if (!this.ignore_notices) {
120
+ $('names').insert({ bottom: '<li>' + TextHelper.truncateName(name) + '</li>' });
121
+ }
122
+ },
123
+
124
+ remove_user: function(name) {
125
+ if (!this.ignore_notices) {
126
+ $$('#names li').each(function(element) { if (element.innerHTML == name) element.remove(); });
127
+ }
128
+ },
129
+
130
+ part_notice: function(part) {
131
+ this.remove_user(part['user']);
132
+ this.add_message(part['user'] + ' has left the room', 'server', part['time']);
133
+ },
134
+
135
+ quit_notice: function(quit) {
136
+ this.remove_user(quit['user']);
137
+ this.add_message(quit['user'] + ' has quit', 'server', quit['time']);
138
+ },
139
+
140
+ notice: function(notice) {
141
+ this.add_message(notice, 'server');
142
+ },
143
+
144
+ error: function(error) {
145
+ this.add_message(error['message'], 'error');
146
+ }
147
+ };
@@ -0,0 +1,55 @@
1
+ var UserCommands = {
2
+ '/emotes': function() {
3
+ var text = '';
4
+ Display.add_message('<strong>Available Emotes</strong> &mdash; Prefix with a : to use', 'help');
5
+ Display.add_message(EmoteHelper.legalEmotes.join(', '), 'help');
6
+ },
7
+
8
+ '/help': function() {
9
+ var help = [];
10
+ Display.add_message('<strong>JsChat Help</strong> &mdash; Type the following commands into the message field:', 'help')
11
+ help.push(['/clear', 'Clears messages']);
12
+ help.push(['/lastlog', 'Shows recent activity']);
13
+ help.push(['/names', 'Refreshes the names list']);
14
+ help.push(['/name new_name', 'Changes your name']);
15
+ help.push(['/emotes', 'Shows available emotes']);
16
+ $A(help).each(function(options) {
17
+ var help_text = '<span class="command">#{command}</span><span class="command_help">#{text}</span>'.interpolate({ command: options[0], text: options[1]});
18
+ Display.add_message(help_text, 'help');
19
+ });
20
+ },
21
+
22
+ '/clear': function() {
23
+ $('messages').innerHTML = '';
24
+ },
25
+
26
+ '/lastlog': function() {
27
+ $('messages').innerHTML = '';
28
+ JsChat.Request.get('/lastlog', function(transport) {
29
+ this.displayMessages(transport.responseText);
30
+ $('names').innerHTML = '';
31
+ this.updateNames();
32
+ }.bind(this));
33
+ },
34
+
35
+ '/(name|nick)\\s+(.*)': function(name) {
36
+ name = name[2];
37
+ new Ajax.Request('/change-name', {
38
+ method: 'post',
39
+ parameters: { name: name },
40
+ onSuccess: function(response) {
41
+ this.displayMessages(response.responseText, function() {
42
+ $('name').innerHTML = name;
43
+ Cookie.create('jschat-name', name, 28, '/');
44
+ });
45
+ }.bind(this),
46
+ onFailure: function() {
47
+ Display.add_message("Server error: couldn't access: #{url}".interpolate({ url: url }), 'server');
48
+ }
49
+ });
50
+ },
51
+
52
+ '/names': function() {
53
+ JsChat.Request.get('/names', function(t) { this.displayMessages(t.responseText); }.bind(this));
54
+ }
55
+ };
@@ -0,0 +1,122 @@
1
+ var TabCompletion = Class.create({
2
+ initialize: function(element) {
3
+ this.element = $(element);
4
+ this.matches = [];
5
+ this.match_offset = 0;
6
+ this.cycling = false;
7
+ this.has_focus = true;
8
+
9
+ document.observe('keydown', this.keyboardEvents.bindAsEventListener(this));
10
+ this.element.observe('focus', this.onFocus.bindAsEventListener(this));
11
+ this.element.observe('blur', this.onBlur.bindAsEventListener(this));
12
+ this.element.observe('click', this.onFocus.bindAsEventListener(this));
13
+ },
14
+
15
+ onBlur: function() {
16
+ this.has_focus = false;
17
+ this.reset();
18
+ },
19
+
20
+ onFocus: function() {
21
+ this.has_focus = true;
22
+ this.reset();
23
+ },
24
+
25
+ tabSearch: function(input) {
26
+ var names = $$('#names li').collect(function(element) { return element.innerHTML });
27
+ return names.findAll(function(name) { return name.toLowerCase().match(input.toLowerCase()) });
28
+ },
29
+
30
+ textToLeft: function() {
31
+ var text = this.element.value;
32
+ var caret_position = FormHelpers.getCaretPosition(this.element);
33
+ if (caret_position < text.length) {
34
+ text = text.slice(0, caret_position);
35
+ }
36
+
37
+ text = text.split(' ').last();
38
+ return text;
39
+ },
40
+
41
+ elementFocused: function(e) {
42
+ if (typeof document.activeElement == 'undefined') {
43
+ return this.has_focus;
44
+ } else {
45
+ return document.activeElement == this.element;
46
+ }
47
+ },
48
+
49
+ keyboardEvents: function(e) {
50
+ if (this.elementFocused()) {
51
+ switch (e.keyCode) {
52
+ case Event.KEY_TAB:
53
+ var caret_position = FormHelpers.getCaretPosition(this.element);
54
+
55
+ if (this.element.value.length > 0) {
56
+ var search_text = '';
57
+ var search_result = '';
58
+ var replace_inline = false;
59
+ var editedText = this.element.value.match(/[^a-z0-9]/i);
60
+
61
+ if (this.cycling) {
62
+ if (this.element.value == '#{last_result}: '.interpolate({ last_result: this.last_result })) {
63
+ editedText = false;
64
+ } else {
65
+ replace_inline = true;
66
+ }
67
+ search_text = this.last_result;
68
+ } else if (editedText && this.matches.length == 0) {
69
+ search_text = this.textToLeft();
70
+ replace_inline = true;
71
+ } else {
72
+ search_text = this.element.value;
73
+ }
74
+
75
+ if (this.matches.length == 0) {
76
+ this.matches = this.tabSearch(search_text);
77
+ search_result = this.matches.first();
78
+ this.cycling = true;
79
+ } else {
80
+ this.match_offset++;
81
+ if (this.match_offset >= this.matches.length) {
82
+ this.match_offset = 0;
83
+ }
84
+ search_result = this.matches[this.match_offset];
85
+ }
86
+
87
+ if (search_result && search_result.length > 0) {
88
+ if (this.cycling && this.last_result) {
89
+ search_text = this.last_result;
90
+ }
91
+ this.last_result = search_result;
92
+
93
+ if (replace_inline) {
94
+ var slice_start = caret_position - search_text.length;
95
+ if (slice_start > 0) {
96
+ this.element.value = this.element.value.substr(0, slice_start) + search_result + this.element.value.substr(caret_position, this.element.value.length);
97
+ FormHelpers.setCaretPosition(this.element, slice_start + search_result.length);
98
+ }
99
+ } else if (!editedText) {
100
+ this.element.value = '#{search_result}: '.interpolate({ search_result: search_result });
101
+ }
102
+ }
103
+ }
104
+
105
+ Event.stop(e);
106
+ return false;
107
+ break;
108
+
109
+ default:
110
+ this.reset();
111
+ break;
112
+ }
113
+ }
114
+ },
115
+
116
+ reset: function() {
117
+ this.matches = [];
118
+ this.match_offset = 0;
119
+ this.last_result = null;
120
+ this.cycling = false;
121
+ }
122
+ });
@@ -0,0 +1,19 @@
1
+ var JsChat = {};
2
+
3
+ document.observe('dom:loaded', function() {
4
+ if ($('post_message')) {
5
+ var chatController = new JsChat.ChatController();
6
+ }
7
+
8
+ if ($('sign-on')) {
9
+ if (Cookie.find('jschat-name')) {
10
+ $('name').value = Cookie.find('jschat-name');
11
+ }
12
+
13
+ if ($('room') && window.location.hash) {
14
+ $('room').value = window.location.hash;
15
+ }
16
+
17
+ var signOnController = new JsChat.SignOnController();
18
+ }
19
+ });
@@ -0,0 +1,3 @@
1
+ body { font-size: 200% }
2
+ input { font-size: 150% }
3
+ #info { display: none }
@@ -0,0 +1,68 @@
1
+ body { margin: 0 auto; padding: 0; font-family: 'Lucida Grande', arial, helvetica, sans-serif; color: #111; text-align: center; }
2
+ html, body { background: #f0f0f0; }
3
+
4
+ h1, h2, h3, h4 { margin: 0; padding: 0; }
5
+
6
+ h1 { text-align: left; margin-left: 20px }
7
+
8
+ .header { position: absolute; top: 0; height: 59px; left: 0; width: 100%; z-index: 10; background-color: #ffc; clear: both; }
9
+ .header img { border: none; margin: 5px 0 0 0 }
10
+ .header h1 { width: 200px; float: left }
11
+ .header .navigation { float: right; list-style-type: none; margin: 18px 0 0 0; padding: 0 }
12
+ .header .navigation li { float: left; margin: 0 20px 0 0; padding: 0 }
13
+ .header .navigation li a { text-decoration: none; color: #fff; background-color: #777; padding: 1px 3px }
14
+ .header .navigation li a:hover { background-color: #fff; color: #555 }
15
+ .header .navigation li#quit-nav a { background-color: #990000 }
16
+ .header .navigation li#quit-nav a:hover { color: #990000; background-color: #fff }
17
+ .header-shadow { width: 100%; height: 6px; position: absolute; top: 59px; left: 0; background-image: url('/images/shadow.png'); background-repeat: repeat-x }
18
+
19
+ .page { margin-top: 60px }
20
+
21
+ #messages { width: 500px; height: 300px; margin: 0 20px 10px 20px; padding: 0; overflow: auto; background-color: #fff; float: left; text-align: left; display: inline; }
22
+ #messages { list-style-type: none; overflow: auto }
23
+ #messages li { padding: 0.25em 0; border-bottom: 1px solid #f0f0f0; float: left; width: 100%; line-height: 1.5em }
24
+ #messages span.user { margin: 0; text-align: left; font-weight: bold; display: inline; float: left }
25
+ #messages .active { color: #000099 }
26
+ #messages .mentioned { color: #cccc00 }
27
+ #messages span.time { text-align: left; margin: 0 10px; display: block; float: left; color: #ccc !important; font-style: normal !important }
28
+ #messages span.message { display: inline; padding: 0 0 0 10px }
29
+ #messages .help { color: #990000 }
30
+ #messages .help span.command { width: 12em; display: block; float: left; font-weight: bold }
31
+ #messages li.server { color: #999; font-style: italic }
32
+ #messages li.error { color: #990000; font-style: italic; font-weight: bold }
33
+ #messages li.server span.time,
34
+ #messages li.error span.time { color: #999 }
35
+ img.inline-image { border: 1px solid #ccc; padding: 2px }
36
+ img.inline-image {
37
+ max-width: 200px;
38
+ width: expression(this.width > 200 ? 200: true);
39
+ }
40
+
41
+ #input { clear: both; text-align: left; margin: 0 0 0 20px; padding: 0; }
42
+ form { margin: 0; padding: 0; }
43
+ #message { width: 100% }
44
+ #message:focus { background-color: #ffc }
45
+
46
+ #info { text-align: left; margin: 0 0 0 20px }
47
+ #room-name { padding: 10px 0; font-size: 125% }
48
+
49
+ ul#names { margin: 0; padding: 0; list-style-type: none; height: 200px; overflow: auto; }
50
+ ul#names li { margin: 0; padding: 0.25em 0; }
51
+ ul#names li.idle { color: #777 }
52
+
53
+ .footer { border-top: 1px solid #ccc; padding: 8px 0 0 0; font-size: 80%; font-style: italic; color: #444; margin: 40px 0 0 0 }
54
+
55
+ /* Front page */
56
+ #sign-on { padding: 10px 0; margin: 10px auto; background-color: #fff; border: 1px solid #ccc; clear: both; text-align: center }
57
+ #sign-on input[type="text"] { width: 12em }
58
+ #sign-on input:focus { background-color: #ffc }
59
+ .content { text-align: left; margin: 0 20px; padding: 5px 0 }
60
+ .content em { padding: 1px 2px; font-style: normal; background-color: #ffc; color: #880000 }
61
+ .content h2 { margin-top: 20px }
62
+
63
+ #feedback .error { padding: 10px; border: 2px solid #990000; background-color: #fff; margin: 10px 0 }
64
+ #loading { background-color: #990000; color: #fff; font-weight: bold; padding: 3px; margin: 0 auto; position: absolute; z-index: 1020; top: 0; right: 10px; border-top: none }
65
+ .angry { color: #990000 }
66
+ .big_message { background-color: #fff; border: 1px solid #ccc; padding: 10px; }
67
+ .big_message h2, .big_message p { margin: 0; padding 0 }
68
+ .big_message h2 { margin-bottom: 10px }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'sprockets'
4
+
5
+ sprockets_root = File.join(File.dirname(__FILE__), '..')
6
+ sprockets_config = YAML.load(IO.read(File.join(sprockets_root, 'config', 'sprockets.yml')))
7
+
8
+ secretary = Sprockets::Secretary.new(
9
+ :root => sprockets_root,
10
+ :load_path => sprockets_config[:load_path],
11
+ :source_files => sprockets_config[:source_files]
12
+ )
13
+
14
+ secretary.concatenation.save_to(File.join(sprockets_root, sprockets_config[:output_file]))
File without changes
@@ -0,0 +1,23 @@
1
+ <div class="content">
2
+ <h2>About</h2>
3
+ <p>JsChat is an <em>open source</em> chat system that uses a simple protocol based on <acronym title="JavaScript Object Notation">JSON</acronym>.</p>
4
+ <p>To download the code and an irssi-like <em>console client</em>, visit <a href="http://github.com/alexyoung/jschat/">GitHub</a>.</p>
5
+ <p>Read more on the <a href="http://blog.jschat.org">JsChat Blog</a>.</p>
6
+ <h2>Try JsChat Now</h2>
7
+ <div id="feedback" class="error" style="display: none"></div>
8
+ <form method="post" action="/identify" id="sign-on">
9
+ Enter name: <input name="name" id="name" value="" type="text" />
10
+ and room: <input name="room" id="room" value="#jschat" type="text" />
11
+ <input type="submit" value="Go" id="sign-on-submit" />
12
+ </form>
13
+ <h2>Features</h2>
14
+ <ul>
15
+ <li>Simple protocol that makes it easy to implement clients and bots</li>
16
+ <li>Console client designed to look and feel like IRC clients</li>
17
+ <li>Web client auto links and displays images/YouTube videos inline</li>
18
+ <li>Protocol designed to be close to executable code, so creating clients and bots is easy</li>
19
+ </ul>
20
+ </div>
21
+ <div class="footer">
22
+ An open source project by <a href="http://helicoid.net">Helicoid</a>
23
+ </div>
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>JsChat iPhone</title>
6
+ <link rel="icon" href="/favicon.ico" />
7
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8
+ <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js" type="text/javascript"></script>
9
+ <script src="/javascripts/all.js?<%= Time.now.to_i %>" type="text/javascript"></script>
10
+ <link href="/stylesheets/screen.css?<%= Time.now.to_i %>" media="screen" rel="stylesheet" type="text/css" />
11
+ <link href="/stylesheets/iphone.css?<%= Time.now.to_i %>" media="screen" rel="stylesheet" type="text/css" />
12
+ </head>
13
+ <body class="iphone">
14
+ <div id="loading" style="display: none">Loading...</div>
15
+ <div class="header">
16
+ <h1><a href="/"><img src="/images/jschat.gif" alt="JsChat" /></a></h1>
17
+ <ul class="navigation">
18
+ <li><a href="/">Home</a></li>
19
+ <li><a href="http://github.com/alexyoung/jschat">Download</a>
20
+ <li id="help-nav" style="display: none"><a href="#" id="help-link">Help</a>
21
+ <li id="quit-nav" style="display: none"><a href="/quit">Quit</a>
22
+ </ul>
23
+ </div>
24
+ <div class="header-shadow"></div>
25
+ <div class="page">
26
+ <%= yield %>
27
+ </div>
28
+ </body>
29
+ </html>
@@ -0,0 +1,29 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title>JsChat</title>
6
+ <link rel="icon" href="/favicon.ico" />
7
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
8
+ <script src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.3/prototype.js" type="text/javascript"></script>
9
+ <script src="/javascripts/all.js?<%= Time.now.to_i %>" type="text/javascript"></script>
10
+ <link href="/stylesheets/screen.css?<%= Time.now.to_i %>" media="screen" rel="stylesheet" type="text/css" />
11
+ </head>
12
+ <body>
13
+ <div id="loading" style="display: none">Loading...</div>
14
+ <div class="header">
15
+ <h1><a href="/"><img src="/images/jschat.gif" alt="JsChat" /></a></h1>
16
+ <ul class="navigation">
17
+ <li><a href="/">Home</a></li>
18
+ <li><a href="http://github.com/alexyoung/jschat">Download</a>
19
+ <li id="help-nav" style="display: none"><a href="#" id="help-link">Help</a>
20
+ <li id="quit-nav" style="display: none"><a href="/quit">Quit</a>
21
+ </ul>
22
+ </div>
23
+ <div class="header-shadow"></div>
24
+ <div class="page">
25
+ <%= yield %>
26
+ </div>
27
+ </body>
28
+ </html>
29
+
@@ -0,0 +1,15 @@
1
+ <ul id="messages">
2
+ </ul>
3
+ <div id="info">
4
+ <h2 id="room-name">Loading...</h2>
5
+ <div id="name" style="display: none"><%= nickname %></div>
6
+ <ul id="names">
7
+ </ul>
8
+ </div>
9
+ <div id="input">
10
+ <form method="post" action="/message" id="post_message">
11
+ <input name="message" id="message" value="" type="text" autocomplete="off" />
12
+ <input name="submit" type="submit" id="send_button" value="Send" />
13
+ </form>
14
+ </div>
15
+