streamit 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/users_controller.rb +83 -0
- data/test/dummy/app/models/stream.rb +3 -0
- data/test/dummy/app/models/user.rb +7 -0
- data/test/dummy/app/views/layouts/application.html.erb +20 -0
- data/test/dummy/app/views/streamit/streams/_stream.html.erb +3 -0
- data/test/dummy/app/views/users/_form.html.erb +25 -0
- data/test/dummy/app/views/users/edit.html.erb +6 -0
- data/test/dummy/app/views/users/index.html.erb +25 -0
- data/test/dummy/app/views/users/new.html.erb +5 -0
- data/test/dummy/app/views/users/show.html.erb +15 -0
- data/test/dummy/config/application.rb +48 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +26 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +10 -0
- data/test/dummy/config/routes.rb +66 -0
- data/test/dummy/db/migrate/20110204210910_create_items.rb +13 -0
- data/test/dummy/db/migrate/20110204210955_create_users.rb +14 -0
- data/test/dummy/db/migrate/20110204211021_create_watchings.rb +14 -0
- data/test/dummy/db/migrate/20110206230646_create_streams.rb +18 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +175 -0
- data/test/dummy/public/stylesheets/scaffold.css +56 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +36 -0
- data/test/store_test.rb +36 -0
- data/test/streamit_test.rb +118 -0
- data/test/support/fixtures.rb +14 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +22 -0
- metadata +89 -9
@@ -0,0 +1,175 @@
|
|
1
|
+
(function() {
|
2
|
+
// Technique from Juriy Zaytsev
|
3
|
+
// http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
|
4
|
+
function isEventSupported(eventName) {
|
5
|
+
var el = document.createElement('div');
|
6
|
+
eventName = 'on' + eventName;
|
7
|
+
var isSupported = (eventName in el);
|
8
|
+
if (!isSupported) {
|
9
|
+
el.setAttribute(eventName, 'return;');
|
10
|
+
isSupported = typeof el[eventName] == 'function';
|
11
|
+
}
|
12
|
+
el = null;
|
13
|
+
return isSupported;
|
14
|
+
}
|
15
|
+
|
16
|
+
function isForm(element) {
|
17
|
+
return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
|
18
|
+
}
|
19
|
+
|
20
|
+
function isInput(element) {
|
21
|
+
if (Object.isElement(element)) {
|
22
|
+
var name = element.nodeName.toUpperCase()
|
23
|
+
return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
|
24
|
+
}
|
25
|
+
else return false
|
26
|
+
}
|
27
|
+
|
28
|
+
var submitBubbles = isEventSupported('submit'),
|
29
|
+
changeBubbles = isEventSupported('change')
|
30
|
+
|
31
|
+
if (!submitBubbles || !changeBubbles) {
|
32
|
+
// augment the Event.Handler class to observe custom events when needed
|
33
|
+
Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
|
34
|
+
function(init, element, eventName, selector, callback) {
|
35
|
+
init(element, eventName, selector, callback)
|
36
|
+
// is the handler being attached to an element that doesn't support this event?
|
37
|
+
if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
|
38
|
+
(!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
|
39
|
+
// "submit" => "emulated:submit"
|
40
|
+
this.eventName = 'emulated:' + this.eventName
|
41
|
+
}
|
42
|
+
}
|
43
|
+
)
|
44
|
+
}
|
45
|
+
|
46
|
+
if (!submitBubbles) {
|
47
|
+
// discover forms on the page by observing focus events which always bubble
|
48
|
+
document.on('focusin', 'form', function(focusEvent, form) {
|
49
|
+
// special handler for the real "submit" event (one-time operation)
|
50
|
+
if (!form.retrieve('emulated:submit')) {
|
51
|
+
form.on('submit', function(submitEvent) {
|
52
|
+
var emulated = form.fire('emulated:submit', submitEvent, true)
|
53
|
+
// if custom event received preventDefault, cancel the real one too
|
54
|
+
if (emulated.returnValue === false) submitEvent.preventDefault()
|
55
|
+
})
|
56
|
+
form.store('emulated:submit', true)
|
57
|
+
}
|
58
|
+
})
|
59
|
+
}
|
60
|
+
|
61
|
+
if (!changeBubbles) {
|
62
|
+
// discover form inputs on the page
|
63
|
+
document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
|
64
|
+
// special handler for real "change" events
|
65
|
+
if (!input.retrieve('emulated:change')) {
|
66
|
+
input.on('change', function(changeEvent) {
|
67
|
+
input.fire('emulated:change', changeEvent, true)
|
68
|
+
})
|
69
|
+
input.store('emulated:change', true)
|
70
|
+
}
|
71
|
+
})
|
72
|
+
}
|
73
|
+
|
74
|
+
function handleRemote(element) {
|
75
|
+
var method, url, params;
|
76
|
+
|
77
|
+
var event = element.fire("ajax:before");
|
78
|
+
if (event.stopped) return false;
|
79
|
+
|
80
|
+
if (element.tagName.toLowerCase() === 'form') {
|
81
|
+
method = element.readAttribute('method') || 'post';
|
82
|
+
url = element.readAttribute('action');
|
83
|
+
params = element.serialize();
|
84
|
+
} else {
|
85
|
+
method = element.readAttribute('data-method') || 'get';
|
86
|
+
url = element.readAttribute('href');
|
87
|
+
params = {};
|
88
|
+
}
|
89
|
+
|
90
|
+
new Ajax.Request(url, {
|
91
|
+
method: method,
|
92
|
+
parameters: params,
|
93
|
+
evalScripts: true,
|
94
|
+
|
95
|
+
onComplete: function(request) { element.fire("ajax:complete", request); },
|
96
|
+
onSuccess: function(request) { element.fire("ajax:success", request); },
|
97
|
+
onFailure: function(request) { element.fire("ajax:failure", request); }
|
98
|
+
});
|
99
|
+
|
100
|
+
element.fire("ajax:after");
|
101
|
+
}
|
102
|
+
|
103
|
+
function handleMethod(element) {
|
104
|
+
var method = element.readAttribute('data-method'),
|
105
|
+
url = element.readAttribute('href'),
|
106
|
+
csrf_param = $$('meta[name=csrf-param]')[0],
|
107
|
+
csrf_token = $$('meta[name=csrf-token]')[0];
|
108
|
+
|
109
|
+
var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
|
110
|
+
element.parentNode.insert(form);
|
111
|
+
|
112
|
+
if (method !== 'post') {
|
113
|
+
var field = new Element('input', { type: 'hidden', name: '_method', value: method });
|
114
|
+
form.insert(field);
|
115
|
+
}
|
116
|
+
|
117
|
+
if (csrf_param) {
|
118
|
+
var param = csrf_param.readAttribute('content'),
|
119
|
+
token = csrf_token.readAttribute('content'),
|
120
|
+
field = new Element('input', { type: 'hidden', name: param, value: token });
|
121
|
+
form.insert(field);
|
122
|
+
}
|
123
|
+
|
124
|
+
form.submit();
|
125
|
+
}
|
126
|
+
|
127
|
+
|
128
|
+
document.on("click", "*[data-confirm]", function(event, element) {
|
129
|
+
var message = element.readAttribute('data-confirm');
|
130
|
+
if (!confirm(message)) event.stop();
|
131
|
+
});
|
132
|
+
|
133
|
+
document.on("click", "a[data-remote]", function(event, element) {
|
134
|
+
if (event.stopped) return;
|
135
|
+
handleRemote(element);
|
136
|
+
event.stop();
|
137
|
+
});
|
138
|
+
|
139
|
+
document.on("click", "a[data-method]", function(event, element) {
|
140
|
+
if (event.stopped) return;
|
141
|
+
handleMethod(element);
|
142
|
+
event.stop();
|
143
|
+
});
|
144
|
+
|
145
|
+
document.on("submit", function(event) {
|
146
|
+
var element = event.findElement(),
|
147
|
+
message = element.readAttribute('data-confirm');
|
148
|
+
if (message && !confirm(message)) {
|
149
|
+
event.stop();
|
150
|
+
return false;
|
151
|
+
}
|
152
|
+
|
153
|
+
var inputs = element.select("input[type=submit][data-disable-with]");
|
154
|
+
inputs.each(function(input) {
|
155
|
+
input.disabled = true;
|
156
|
+
input.writeAttribute('data-original-value', input.value);
|
157
|
+
input.value = input.readAttribute('data-disable-with');
|
158
|
+
});
|
159
|
+
|
160
|
+
var element = event.findElement("form[data-remote]");
|
161
|
+
if (element) {
|
162
|
+
handleRemote(element);
|
163
|
+
event.stop();
|
164
|
+
}
|
165
|
+
});
|
166
|
+
|
167
|
+
document.on("ajax:after", "form", function(event, element) {
|
168
|
+
var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
|
169
|
+
inputs.each(function(input) {
|
170
|
+
input.value = input.readAttribute('data-original-value');
|
171
|
+
input.removeAttribute('data-original-value');
|
172
|
+
input.disabled = false;
|
173
|
+
});
|
174
|
+
});
|
175
|
+
})();
|
@@ -0,0 +1,56 @@
|
|
1
|
+
body { background-color: #fff; color: #333; }
|
2
|
+
|
3
|
+
body, p, ol, ul, td {
|
4
|
+
font-family: verdana, arial, helvetica, sans-serif;
|
5
|
+
font-size: 13px;
|
6
|
+
line-height: 18px;
|
7
|
+
}
|
8
|
+
|
9
|
+
pre {
|
10
|
+
background-color: #eee;
|
11
|
+
padding: 10px;
|
12
|
+
font-size: 11px;
|
13
|
+
}
|
14
|
+
|
15
|
+
a { color: #000; }
|
16
|
+
a:visited { color: #666; }
|
17
|
+
a:hover { color: #fff; background-color:#000; }
|
18
|
+
|
19
|
+
div.field, div.actions {
|
20
|
+
margin-bottom: 10px;
|
21
|
+
}
|
22
|
+
|
23
|
+
#notice {
|
24
|
+
color: green;
|
25
|
+
}
|
26
|
+
|
27
|
+
.field_with_errors {
|
28
|
+
padding: 2px;
|
29
|
+
background-color: red;
|
30
|
+
display: table;
|
31
|
+
}
|
32
|
+
|
33
|
+
#error_explanation {
|
34
|
+
width: 450px;
|
35
|
+
border: 2px solid red;
|
36
|
+
padding: 7px;
|
37
|
+
padding-bottom: 0;
|
38
|
+
margin-bottom: 20px;
|
39
|
+
background-color: #f0f0f0;
|
40
|
+
}
|
41
|
+
|
42
|
+
#error_explanation h2 {
|
43
|
+
text-align: left;
|
44
|
+
font-weight: bold;
|
45
|
+
padding: 5px 5px 5px 15px;
|
46
|
+
font-size: 12px;
|
47
|
+
margin: -7px;
|
48
|
+
margin-bottom: 0px;
|
49
|
+
background-color: #c00;
|
50
|
+
color: #fff;
|
51
|
+
}
|
52
|
+
|
53
|
+
#error_explanation ul li {
|
54
|
+
font-size: 12px;
|
55
|
+
list-style: square;
|
56
|
+
}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
|
+
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
|
+
require 'rails/commands'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class NavigationTest < ActiveSupport::IntegrationCase
|
4
|
+
|
5
|
+
def register_new_user
|
6
|
+
visit "/users/new"
|
7
|
+
fill_in "Name", :with => "davis"
|
8
|
+
click_button "Create User"
|
9
|
+
end
|
10
|
+
|
11
|
+
should "fetch recent streams" do
|
12
|
+
register_new_user
|
13
|
+
register_new_user
|
14
|
+
visit "/streamit/fetch"
|
15
|
+
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
should "fetch streams in last ? seconds" do
|
19
|
+
Timecop.freeze(Time.now - 30.seconds) do
|
20
|
+
register_new_user
|
21
|
+
end
|
22
|
+
register_new_user
|
23
|
+
register_new_user
|
24
|
+
visit "/streamit/fetch?ago=30"
|
25
|
+
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
26
|
+
end
|
27
|
+
|
28
|
+
should "fetch streams from after an id" do
|
29
|
+
register_new_user
|
30
|
+
register_new_user
|
31
|
+
register_new_user
|
32
|
+
visit "/streamit/fetch?after=#{Stream.last.id}"
|
33
|
+
assert page.has_selector?("li.stream", :count => 2), "Expected 2 streams, Got:\n#{page.body.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/test/store_test.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class StoreTest < ActiveSupport::TestCase
|
4
|
+
setup do
|
5
|
+
@user = TestUser.create(:name => 'davis')
|
6
|
+
end
|
7
|
+
|
8
|
+
def default_args
|
9
|
+
{ :stream_type => 'streamit.example',
|
10
|
+
:actor => @user,
|
11
|
+
:receiver => @user,
|
12
|
+
:subject => @user,
|
13
|
+
:started_at => Time.now }
|
14
|
+
end
|
15
|
+
|
16
|
+
def store!(args=default_args)
|
17
|
+
stream = Stream.new(args)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "set the type" do
|
21
|
+
assert_equal "streamit.example", store!.stream_type
|
22
|
+
end
|
23
|
+
|
24
|
+
should "set started at" do
|
25
|
+
assert_kind_of Time, store!.started_at
|
26
|
+
end
|
27
|
+
|
28
|
+
should "translate type to meaningful words" do
|
29
|
+
I18n.backend.store_translations :en,
|
30
|
+
:streamit => { :example => "just an example" }
|
31
|
+
|
32
|
+
assert_equal "just an example", store!.stream_type_in_words
|
33
|
+
I18n.reload!
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class StreamitTest < ActiveSupport::TestCase
|
4
|
+
def stream_store
|
5
|
+
Streamit.store
|
6
|
+
end
|
7
|
+
|
8
|
+
context "when user watches an item" do
|
9
|
+
setup do
|
10
|
+
TestWatching.class_eval do
|
11
|
+
stream :create, :actor => :watcher, :subject => :watched_item
|
12
|
+
end
|
13
|
+
@watch = TestWatching.new(:watcher => TestUser.create!, :watched_item => TestItem.create!)
|
14
|
+
end
|
15
|
+
|
16
|
+
should "create a stream if watching is created successfully" do
|
17
|
+
@watch.save
|
18
|
+
stream = stream_store.last
|
19
|
+
assert_not_nil stream
|
20
|
+
assert_equal "streamit.testwatchings.create", stream.stream_type
|
21
|
+
assert_equal @watch.watcher, stream.actor
|
22
|
+
assert_equal @watch.watched_item, stream.subject
|
23
|
+
assert_nil stream.receiver
|
24
|
+
end
|
25
|
+
|
26
|
+
should "not create a stream if failed to create a watching" do
|
27
|
+
TestWatching.class_eval do
|
28
|
+
before_create { return false }
|
29
|
+
end
|
30
|
+
assert_no_difference("stream_store.count") { @watch.save }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when create or update a user" do
|
35
|
+
setup do
|
36
|
+
@user = TestUser.new
|
37
|
+
@user.singleton_class.class_eval do
|
38
|
+
def self.name; "TestUser"; end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
should "create a stream" do
|
43
|
+
@user.singleton_class.class_eval do
|
44
|
+
stream :create
|
45
|
+
end
|
46
|
+
@user.save
|
47
|
+
stream = stream_store.last
|
48
|
+
assert_not_nil stream
|
49
|
+
assert_equal "streamit.testusers.create", stream.stream_type
|
50
|
+
assert_equal @user, stream.actor
|
51
|
+
assert_nil stream.subject
|
52
|
+
assert_nil stream.receiver
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when user updates her attributes" do
|
56
|
+
setup do
|
57
|
+
@user.save
|
58
|
+
end
|
59
|
+
|
60
|
+
should "create a stream the attribute specified has changed" do
|
61
|
+
@user.singleton_class.class_eval do
|
62
|
+
stream :update, :attributes => :image_url
|
63
|
+
end
|
64
|
+
@user.image_url = "image"
|
65
|
+
@user.save
|
66
|
+
stream = stream_store.last
|
67
|
+
assert_not_nil stream
|
68
|
+
assert_equal "streamit.testusers.update.image_url", stream.stream_type
|
69
|
+
assert_equal @user, stream.actor
|
70
|
+
assert_nil stream.subject
|
71
|
+
assert_nil stream.receiver
|
72
|
+
end
|
73
|
+
|
74
|
+
should "create a stream if any attributes have changed" do
|
75
|
+
@user.singleton_class.class_eval do
|
76
|
+
stream :update
|
77
|
+
end
|
78
|
+
@user.name = "davis"
|
79
|
+
@user.save
|
80
|
+
stream = stream_store.last
|
81
|
+
assert_not_nil stream
|
82
|
+
assert_equal "streamit.testusers.update.default", stream.stream_type
|
83
|
+
assert_equal @user, stream.actor
|
84
|
+
assert_nil stream.subject
|
85
|
+
assert_nil stream.receiver
|
86
|
+
end
|
87
|
+
|
88
|
+
should "create a stream if any attributes specified have changed" do
|
89
|
+
@user.singleton_class.class_eval do
|
90
|
+
stream :update, :attributes => [:name, :image_url]
|
91
|
+
end
|
92
|
+
@user.name = "davis"
|
93
|
+
@user.save
|
94
|
+
stream = stream_store.last
|
95
|
+
assert_not_nil stream
|
96
|
+
assert_equal "streamit.testusers.update.default", stream.stream_type
|
97
|
+
assert_equal @user, stream.actor
|
98
|
+
assert_nil stream.subject
|
99
|
+
assert_nil stream.receiver
|
100
|
+
end
|
101
|
+
|
102
|
+
should "not create a stream if no attributes has changed" do
|
103
|
+
assert_no_difference("stream_store.count") { @user.save }
|
104
|
+
end
|
105
|
+
|
106
|
+
should "not create a stream if no attributes specified has changed" do
|
107
|
+
@user.singleton_class.class_eval do
|
108
|
+
stream :update, :attributes => :name
|
109
|
+
end
|
110
|
+
@user.image_url = "image"
|
111
|
+
@user.save
|
112
|
+
assert_equal 0, stream_store.count
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class TestUser < ActiveRecord::Base
|
2
|
+
self.table_name = "users"
|
3
|
+
end
|
4
|
+
|
5
|
+
class TestItem < ActiveRecord::Base
|
6
|
+
self.table_name = "items"
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestWatching < ActiveRecord::Base
|
10
|
+
self.table_name = "watchings"
|
11
|
+
|
12
|
+
belongs_to :watcher, :class_name => "TestUser", :foreign_key => "user_id"
|
13
|
+
belongs_to :watched_item, :class_name => "TestItem", :foreign_key => "item_id"
|
14
|
+
end
|