t3-rails 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +74 -0
- data/Rakefile +41 -0
- data/lib/generators/t3/behavior_generator.rb +17 -0
- data/lib/generators/t3/bootstrap_generator.rb +42 -0
- data/lib/generators/t3/generator_helper.rb +19 -0
- data/lib/generators/t3/module_generator.rb +17 -0
- data/lib/generators/t3/service_generator.rb +17 -0
- data/lib/generators/templates/behavior.js +45 -0
- data/lib/generators/templates/module.js +45 -0
- data/lib/generators/templates/service.js +45 -0
- data/lib/t3/rails.rb +8 -0
- data/lib/t3/rails/version.rb +6 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +27 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/log/development.log +4 -0
- data/test/dummy/log/test.log +3962 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/tmp/app/assets/javascripts/behaviors/validate.js +45 -0
- data/test/generators/behavior_generator_test.rb +21 -0
- data/test/generators/bootstrap_generator_test.rb +75 -0
- data/test/generators/module_generator_test.rb +21 -0
- data/test/generators/service_generator_test.rb +21 -0
- data/test/t3_rails_test.rb +13 -0
- data/test/test_helper.rb +18 -0
- data/vendor/assets/javascripts/t3-testing.js +459 -0
- data/vendor/assets/javascripts/t3.js +1233 -0
- data/vendor/assets/javascripts/t3.min.js +18 -0
- metadata +172 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/404.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
62
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/422.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The change you wanted was rejected.</h1>
|
62
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/500.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>We're sorry, but something went wrong.</h1>
|
62
|
+
</div>
|
63
|
+
<p>If you are the application owner check the logs for more information.</p>
|
64
|
+
</div>
|
65
|
+
</body>
|
66
|
+
</html>
|
File without changes
|
@@ -0,0 +1,45 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Description of file
|
3
|
+
* @author your name
|
4
|
+
*/
|
5
|
+
|
6
|
+
/*global Box*/
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Description of behavior.
|
10
|
+
*/
|
11
|
+
Box.Application.addBehavior('validate', function(context) {
|
12
|
+
|
13
|
+
'use strict';
|
14
|
+
|
15
|
+
//-----------------------------------------------------------
|
16
|
+
// Private
|
17
|
+
//-----------------------------------------------------------
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Description of function.
|
21
|
+
* @param {type} name Description
|
22
|
+
* @returns {type} Description
|
23
|
+
* @private
|
24
|
+
*/
|
25
|
+
function privateFunction(name) {
|
26
|
+
|
27
|
+
}
|
28
|
+
|
29
|
+
//-----------------------------------------------------------
|
30
|
+
// Public
|
31
|
+
//-----------------------------------------------------------
|
32
|
+
|
33
|
+
return {
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Description of method.
|
37
|
+
* @param {type} name Description
|
38
|
+
* @returns {type} Description
|
39
|
+
*/
|
40
|
+
method: function(name) {
|
41
|
+
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
});
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'generators/t3/behavior_generator'
|
3
|
+
|
4
|
+
class BehaviorGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests T3::Generators::BehaviorGenerator
|
6
|
+
|
7
|
+
destination File.join(Rails.root, 'tmp')
|
8
|
+
setup :prepare_destination
|
9
|
+
|
10
|
+
test 'service file is created' do
|
11
|
+
run_generator %w(validate)
|
12
|
+
assert_file "#{install_path}/behaviors/validate.js", %r{addBehavior\('validate'}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def install_path
|
18
|
+
'app/assets/javascripts'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'generators/t3/bootstrap_generator'
|
3
|
+
|
4
|
+
class BootstrapGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests T3::Generators::BootstrapGenerator
|
6
|
+
|
7
|
+
destination File.join(Rails.root, 'tmp')
|
8
|
+
setup :prepare_destination
|
9
|
+
|
10
|
+
def prepare_destination
|
11
|
+
super
|
12
|
+
assets_dir = "#{destination_root}/app/assets"
|
13
|
+
mkdir_p assets_dir
|
14
|
+
cp_r Rails.root.join('app', 'assets', 'javascripts'), assets_dir
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'directories are created' do
|
18
|
+
run_generator
|
19
|
+
assert_directories
|
20
|
+
end
|
21
|
+
|
22
|
+
test '.gitkeep files are created' do
|
23
|
+
run_generator
|
24
|
+
assert_gitkeep_files
|
25
|
+
end
|
26
|
+
|
27
|
+
test '.gitkeep files are not created when skip_git option is true' do
|
28
|
+
run_generator %w(-g)
|
29
|
+
assert_no_gitkeep_files
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'files are required in application.js' do
|
33
|
+
run_generator
|
34
|
+
assert_application_requires
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def components
|
40
|
+
%W{behaviors modules services}
|
41
|
+
end
|
42
|
+
|
43
|
+
def install_path
|
44
|
+
'app/assets/javascripts'
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_directories(options = {})
|
48
|
+
path = install_path
|
49
|
+
components.each { |c| assert_directory "#{path}/#{c}" }
|
50
|
+
end
|
51
|
+
|
52
|
+
def assert_gitkeep_files(options={})
|
53
|
+
path = install_path
|
54
|
+
components.each { |c| assert_file "#{path}/#{c}/.gitkeep" }
|
55
|
+
end
|
56
|
+
|
57
|
+
def assert_no_gitkeep_files(options={})
|
58
|
+
path = install_path
|
59
|
+
components.each { |c| assert_no_file "#{path}/#{c}/.gitkeep" }
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert_application_requires
|
63
|
+
file = "#{install_path}/application.js"
|
64
|
+
assert_file file
|
65
|
+
|
66
|
+
# Ensure requires are not repeated
|
67
|
+
absolute = File.expand_path(file, destination_root).shellescape
|
68
|
+
assert_no_match %r{(^//= require t3$[^\z]+){2,}\z}, File.read(absolute)
|
69
|
+
|
70
|
+
components.each do |c|
|
71
|
+
assert_file file, %r{(//= require_tree ./#{c}){1}}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'generators/t3/module_generator'
|
3
|
+
|
4
|
+
class ModuleGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests T3::Generators::ModuleGenerator
|
6
|
+
|
7
|
+
destination File.join(Rails.root, 'tmp')
|
8
|
+
setup :prepare_destination
|
9
|
+
|
10
|
+
test 'module file is created' do
|
11
|
+
run_generator %w(cc_form)
|
12
|
+
assert_file "#{install_path}/modules/cc_form.js", %r{addModule\('cc_form'}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def install_path
|
18
|
+
'app/assets/javascripts'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'generators/t3/service_generator'
|
3
|
+
|
4
|
+
class ServiceGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests T3::Generators::ServiceGenerator
|
6
|
+
|
7
|
+
destination File.join(Rails.root, 'tmp')
|
8
|
+
setup :prepare_destination
|
9
|
+
|
10
|
+
test 'service file is created' do
|
11
|
+
run_generator %w(credit_card)
|
12
|
+
assert_file "#{install_path}/services/credit_card.js", %r{addService\('credit_card'}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def install_path
|
18
|
+
'app/assets/javascripts'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class T3RailsTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
@app = Dummy::Application
|
6
|
+
end
|
7
|
+
|
8
|
+
test 't3 is found as an asset' do
|
9
|
+
assert_not_nil @app.assets['t3']
|
10
|
+
assert_not_nil @app.assets['t3.min']
|
11
|
+
assert_not_nil @app.assets['t3-testing']
|
12
|
+
end
|
13
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Configure Rails Environment
|
2
|
+
ENV["RAILS_ENV"] = "test"
|
3
|
+
|
4
|
+
require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
|
5
|
+
require "rails/test_help"
|
6
|
+
|
7
|
+
# Filter out Minitest backtrace while allowing backtrace from other libraries
|
8
|
+
# to be shown.
|
9
|
+
Minitest.backtrace_filter = Minitest::BacktraceFilter.new
|
10
|
+
|
11
|
+
# Load support files
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
13
|
+
|
14
|
+
# Load fixtures from the engine
|
15
|
+
if ActiveSupport::TestCase.respond_to?(:fixture_path=)
|
16
|
+
ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
|
17
|
+
ActiveSupport::TestCase.fixtures :all
|
18
|
+
end
|
@@ -0,0 +1,459 @@
|
|
1
|
+
/*! t3 v 1.4.0*/
|
2
|
+
/*!
|
3
|
+
Copyright 2015 Box, Inc. All rights reserved.
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
*/
|
17
|
+
// Start wrapper
|
18
|
+
// We use this to make sure we don't assign globals unless we actually want to
|
19
|
+
(function(window) {
|
20
|
+
|
21
|
+
/**
|
22
|
+
* @fileoverview Base namespaces for Box JavaScript.
|
23
|
+
* @author Box
|
24
|
+
*/
|
25
|
+
|
26
|
+
/* eslint-disable no-unused-vars */
|
27
|
+
|
28
|
+
/**
|
29
|
+
* The one global object for Box JavaScript.
|
30
|
+
* @namespace
|
31
|
+
*/
|
32
|
+
var Box = {};
|
33
|
+
/* eslint-enable no-unused-vars */
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @fileoverview Definition of a custom event type. This is used as a utility
|
37
|
+
* throughout the framework whenever custom events are used. It is intended to
|
38
|
+
* be inherited from, either through the prototype or via mixin.
|
39
|
+
* @author Box
|
40
|
+
*/
|
41
|
+
|
42
|
+
Box.EventTarget = (function() {
|
43
|
+
|
44
|
+
'use strict';
|
45
|
+
|
46
|
+
/**
|
47
|
+
* An object that is capable of generating custom events and also
|
48
|
+
* executing handlers for events when they occur.
|
49
|
+
* @constructor
|
50
|
+
*/
|
51
|
+
function EventTarget() {
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Map of events to handlers. The keys in the object are the event names.
|
55
|
+
* The values in the object are arrays of event handler functions.
|
56
|
+
* @type {Object}
|
57
|
+
* @private
|
58
|
+
*/
|
59
|
+
this._handlers = {};
|
60
|
+
}
|
61
|
+
|
62
|
+
EventTarget.prototype = {
|
63
|
+
|
64
|
+
// restore constructor
|
65
|
+
constructor: EventTarget,
|
66
|
+
|
67
|
+
/**
|
68
|
+
* Adds a new event handler for a particular type of event.
|
69
|
+
* @param {string} type The name of the event to listen for.
|
70
|
+
* @param {Function} handler The function to call when the event occurs.
|
71
|
+
* @returns {void}
|
72
|
+
*/
|
73
|
+
on: function(type, handler) {
|
74
|
+
|
75
|
+
var handlers = this._handlers[type],
|
76
|
+
i,
|
77
|
+
len;
|
78
|
+
|
79
|
+
if (typeof handlers === 'undefined') {
|
80
|
+
handlers = this._handlers[type] = [];
|
81
|
+
}
|
82
|
+
|
83
|
+
for (i = 0, len = handlers.length; i < len; i++) {
|
84
|
+
if (handlers[i] === handler) {
|
85
|
+
// prevent duplicate handlers
|
86
|
+
return;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
handlers.push(handler);
|
91
|
+
},
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Fires an event with the given name and data.
|
95
|
+
* @param {string} type The type of event to fire.
|
96
|
+
* @param {Object} [data] An object with properties that should end up on
|
97
|
+
* the event object for the given event.
|
98
|
+
* @returns {void}
|
99
|
+
*/
|
100
|
+
fire: function(type, data) {
|
101
|
+
|
102
|
+
var handlers,
|
103
|
+
i,
|
104
|
+
len,
|
105
|
+
event = {
|
106
|
+
type: type,
|
107
|
+
data: data
|
108
|
+
};
|
109
|
+
|
110
|
+
// if there are handlers for the event, call them in order
|
111
|
+
handlers = this._handlers[event.type];
|
112
|
+
if (handlers instanceof Array) {
|
113
|
+
// @NOTE: do a concat() here to create a copy of the handlers array,
|
114
|
+
// so that if another handler is removed of the same type, it doesn't
|
115
|
+
// interfere with the handlers array during this loop
|
116
|
+
handlers = handlers.concat();
|
117
|
+
for (i = 0, len = handlers.length; i < len; i++) {
|
118
|
+
handlers[i].call(this, event);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
},
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Removes an event handler from a given event.
|
125
|
+
* @param {string} type The name of the event to remove from.
|
126
|
+
* @param {Function} handler The function to remove as a handler.
|
127
|
+
* @returns {void}
|
128
|
+
*/
|
129
|
+
off: function(type, handler) {
|
130
|
+
|
131
|
+
var handlers = this._handlers[type],
|
132
|
+
i,
|
133
|
+
len;
|
134
|
+
|
135
|
+
if (handlers instanceof Array) {
|
136
|
+
for (i = 0, len = handlers.length; i < len; i++) {
|
137
|
+
if (handlers[i] === handler) {
|
138
|
+
handlers.splice(i, 1);
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
};
|
145
|
+
|
146
|
+
return EventTarget;
|
147
|
+
|
148
|
+
}());
|
149
|
+
|
150
|
+
/**
|
151
|
+
* @fileoverview DOM abstraction to use jquery to add and remove event listeners
|
152
|
+
* in T3
|
153
|
+
* @author jdivock
|
154
|
+
*/
|
155
|
+
|
156
|
+
Box.JQueryDOM = (function() {
|
157
|
+
'use strict';
|
158
|
+
|
159
|
+
return {
|
160
|
+
|
161
|
+
type: 'jquery',
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Returns the first element that is a descendant of the element
|
165
|
+
* on which it is invoked that matches the specified group of selectors.
|
166
|
+
* @param {HTMLElement} root parent element to query off of
|
167
|
+
* @param {string} selector query string to match on
|
168
|
+
*
|
169
|
+
* @returns {HTMLElement} first element found matching query
|
170
|
+
*/
|
171
|
+
query: function(root, selector) {
|
172
|
+
// Aligning with native which returns null if not found
|
173
|
+
return $(root).find(selector)[0] || null;
|
174
|
+
},
|
175
|
+
|
176
|
+
/**
|
177
|
+
* Returns a non-live NodeList of all elements descended from the
|
178
|
+
* element on which it is invoked that match the specified group of CSS selectors.
|
179
|
+
* @param {HTMLElement} root parent element to query off of
|
180
|
+
* @param {string} selector query string to match on
|
181
|
+
*
|
182
|
+
* @returns {Array} elements found matching query
|
183
|
+
*/
|
184
|
+
queryAll: function(root, selector) {
|
185
|
+
return $.makeArray($(root).find(selector));
|
186
|
+
},
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Adds event listener to element via jquery
|
190
|
+
* @param {HTMLElement} element Target to attach listener to
|
191
|
+
* @param {string} type Name of the action to listen for
|
192
|
+
* @param {function} listener Function to be executed on action
|
193
|
+
*
|
194
|
+
* @returns {void}
|
195
|
+
*/
|
196
|
+
on: function(element, type, listener) {
|
197
|
+
$(element).on(type, listener);
|
198
|
+
},
|
199
|
+
|
200
|
+
/**
|
201
|
+
* Removes event listener to element via jquery
|
202
|
+
* @param {HTMLElement} element Target to remove listener from
|
203
|
+
* @param {string} type Name of the action remove listener from
|
204
|
+
* @param {function} listener Function to be removed from action
|
205
|
+
*
|
206
|
+
* @returns {void}
|
207
|
+
*/
|
208
|
+
off: function(element, type, listener) {
|
209
|
+
$(element).off(type, listener);
|
210
|
+
}
|
211
|
+
};
|
212
|
+
}());
|
213
|
+
|
214
|
+
Box.DOM = Box.JQueryDOM;
|
215
|
+
|
216
|
+
/**
|
217
|
+
* @fileoverview Fake application to use during testing
|
218
|
+
* @author Box
|
219
|
+
*/
|
220
|
+
|
221
|
+
(function() {
|
222
|
+
|
223
|
+
'use strict';
|
224
|
+
|
225
|
+
/*
|
226
|
+
* When testing actual Application, it should be included after to overwrite this stub.
|
227
|
+
*/
|
228
|
+
Box.Application = (function() {
|
229
|
+
|
230
|
+
var services = {},
|
231
|
+
modules = {},
|
232
|
+
behaviors = {};
|
233
|
+
|
234
|
+
return {
|
235
|
+
|
236
|
+
/**
|
237
|
+
* Resets the application stub back to a clean state. Will also remove pre-registered components.
|
238
|
+
* @returns {void}
|
239
|
+
*/
|
240
|
+
reset: function() {
|
241
|
+
services = {};
|
242
|
+
modules = {};
|
243
|
+
behaviors = {};
|
244
|
+
},
|
245
|
+
|
246
|
+
/**
|
247
|
+
* Registers a service to the application stub
|
248
|
+
* @param {string} serviceName The name of the service
|
249
|
+
* @param {Function} creator The service creator function
|
250
|
+
* @returns {void}
|
251
|
+
*/
|
252
|
+
addService: function(serviceName, creator) {
|
253
|
+
services[serviceName] = {
|
254
|
+
creator: creator
|
255
|
+
};
|
256
|
+
},
|
257
|
+
|
258
|
+
/**
|
259
|
+
* Registers a module to the application stub
|
260
|
+
* @param {string} moduleName The name of the module
|
261
|
+
* @param {Function} creator The behavior creator function
|
262
|
+
* @returns {void}
|
263
|
+
*/
|
264
|
+
addModule: function(moduleName, creator) {
|
265
|
+
modules[moduleName] = {
|
266
|
+
creator: creator
|
267
|
+
};
|
268
|
+
},
|
269
|
+
|
270
|
+
/**
|
271
|
+
* Registers a behavior to the application stub
|
272
|
+
* @param {string} behaviorName The name of the behavior
|
273
|
+
* @param {Function} creator The behavior creator function
|
274
|
+
* @returns {void}
|
275
|
+
*/
|
276
|
+
addBehavior: function(behaviorName, creator) {
|
277
|
+
behaviors[behaviorName] = {
|
278
|
+
creator: creator
|
279
|
+
};
|
280
|
+
},
|
281
|
+
|
282
|
+
/**
|
283
|
+
* Will create a new instance of a service with the given application context
|
284
|
+
* @param {string} serviceName The name of the service being created
|
285
|
+
* @param {Object} application The application context object (usually a TestServiceProvider)
|
286
|
+
* @returns {?Object} The service object
|
287
|
+
*/
|
288
|
+
getServiceForTest: function(serviceName, application) {
|
289
|
+
var serviceData = services[serviceName];
|
290
|
+
if (serviceData) {
|
291
|
+
return services[serviceName].creator(application);
|
292
|
+
}
|
293
|
+
return null;
|
294
|
+
},
|
295
|
+
|
296
|
+
/**
|
297
|
+
* Will create a new instance of a module with a given context
|
298
|
+
* @param {string} moduleName The name of the module being created
|
299
|
+
* @param {Object} context The context object (usually a TestServiceProvider)
|
300
|
+
* @returns {?Object} The module object
|
301
|
+
*/
|
302
|
+
getModuleForTest: function(moduleName, context) {
|
303
|
+
var module = modules[moduleName].creator(context);
|
304
|
+
|
305
|
+
if (!context.getElement) {
|
306
|
+
// Add in a default getElement function that matches the first module element
|
307
|
+
// Developer should stub this out if there are more than one instance of this module
|
308
|
+
context.getElement = function() {
|
309
|
+
return document.querySelector('[data-module="' + moduleName + '"]');
|
310
|
+
};
|
311
|
+
}
|
312
|
+
return module;
|
313
|
+
},
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Will create a new instance of a behavior with a given context
|
317
|
+
* @param {string} behaviorName The name of the behavior being created
|
318
|
+
* @param {Object} context The context object (usually a TestServiceProvider)
|
319
|
+
* @returns {?Object} The behavior object
|
320
|
+
*/
|
321
|
+
getBehaviorForTest: function(behaviorName, context) {
|
322
|
+
var behaviorData = behaviors[behaviorName];
|
323
|
+
if (behaviorData) {
|
324
|
+
// getElement on behaviors must be stubbed
|
325
|
+
if (!context.getElement) {
|
326
|
+
context.getElement = function() {
|
327
|
+
throw new Error('You must stub `getElement` for behaviors.');
|
328
|
+
};
|
329
|
+
}
|
330
|
+
return behaviors[behaviorName].creator(context);
|
331
|
+
}
|
332
|
+
return null;
|
333
|
+
}
|
334
|
+
|
335
|
+
};
|
336
|
+
|
337
|
+
}());
|
338
|
+
|
339
|
+
}());
|
340
|
+
|
341
|
+
/**
|
342
|
+
* @fileoverview A service provider that also contains a few pre-stubbed functions
|
343
|
+
* @author Box
|
344
|
+
*/
|
345
|
+
|
346
|
+
(function() {
|
347
|
+
|
348
|
+
'use strict';
|
349
|
+
|
350
|
+
// We should use a reference directly the original application-stub object in case Box.Application gets stubbed out
|
351
|
+
var application = Box.Application;
|
352
|
+
|
353
|
+
// function stubs that are automatically included on a TestServiceProvider
|
354
|
+
var APPLICATION_CONTEXT_STUBS = [
|
355
|
+
// Shared between Application and Context
|
356
|
+
'broadcast', 'getGlobalConfig', 'reportError',
|
357
|
+
|
358
|
+
// Application (only ones that should be called from a service)
|
359
|
+
'start', 'stop', 'startAll', 'stopAll', 'isStarted',
|
360
|
+
|
361
|
+
// Context (module/behavior only) - getElement done separately
|
362
|
+
'getConfig'
|
363
|
+
];
|
364
|
+
|
365
|
+
/**
|
366
|
+
* Return a function stub that will throw an error if the test code does not properly mock out dependencies.
|
367
|
+
* @param {string} method The name of the method being invoked
|
368
|
+
* @returns {Function} A function stub
|
369
|
+
*/
|
370
|
+
function functionStub(method) {
|
371
|
+
return (function(methodKey) {
|
372
|
+
return function() {
|
373
|
+
throw new Error('Unexpected call to method "' + methodKey + '". You must stub this method out.');
|
374
|
+
};
|
375
|
+
}(method));
|
376
|
+
}
|
377
|
+
|
378
|
+
/**
|
379
|
+
* This object is used as a stub for application/context that is normally passed into services/modules/behaviors at create time.
|
380
|
+
* It exposes the stubbed services passed in through the getService() method and can also return real services if necessary.
|
381
|
+
* @param {Object} serviceStubs A map of service stubs
|
382
|
+
* @constructor
|
383
|
+
*/
|
384
|
+
Box.TestServiceProvider = function(serviceStubs) {
|
385
|
+
this.stubs = serviceStubs || {};
|
386
|
+
};
|
387
|
+
|
388
|
+
Box.TestServiceProvider.prototype = {
|
389
|
+
|
390
|
+
/**
|
391
|
+
* Will retrieve either a service stub (prioritized) or the real service. Returns null if neither exists.
|
392
|
+
* @param {string} serviceName The name of the service being retrieved
|
393
|
+
* @returns {?Object} A service object or null if none exists
|
394
|
+
*/
|
395
|
+
getService: function(serviceName) {
|
396
|
+
var service = this.stubs[serviceName],
|
397
|
+
preRegisteredService;
|
398
|
+
|
399
|
+
// Return a service stub if found
|
400
|
+
if (service) {
|
401
|
+
return service;
|
402
|
+
}
|
403
|
+
|
404
|
+
// Return a real registered service, if it exists (sometimes you want the real deal, i.e. utils)
|
405
|
+
preRegisteredService = application.getServiceForTest(serviceName, this);
|
406
|
+
if (preRegisteredService) {
|
407
|
+
return preRegisteredService;
|
408
|
+
}
|
409
|
+
|
410
|
+
return null;
|
411
|
+
},
|
412
|
+
|
413
|
+
/**
|
414
|
+
* Retrieves a global var (this is the actual implementation for convenience in testing)
|
415
|
+
* @param {string} name The name of the global
|
416
|
+
* @returns {?*} The global object referenced or null if it does not exist
|
417
|
+
*/
|
418
|
+
getGlobal: function(name) {
|
419
|
+
if (name in window) {
|
420
|
+
return window[name];
|
421
|
+
} else {
|
422
|
+
return null;
|
423
|
+
}
|
424
|
+
}
|
425
|
+
};
|
426
|
+
|
427
|
+
// Add stubbed functions onto prototype for testing convenience
|
428
|
+
var stubName;
|
429
|
+
for (var i = 0, len = APPLICATION_CONTEXT_STUBS.length; i < len; i++) {
|
430
|
+
stubName = APPLICATION_CONTEXT_STUBS[i];
|
431
|
+
Box.TestServiceProvider.prototype[stubName] = functionStub(stubName);
|
432
|
+
}
|
433
|
+
|
434
|
+
}());
|
435
|
+
|
436
|
+
if (typeof define === 'function' && define.amd) {
|
437
|
+
// AMD
|
438
|
+
define('t3', [], function() {
|
439
|
+
return Box;
|
440
|
+
});
|
441
|
+
} else if (typeof module === 'object' && typeof module.exports === 'object') {
|
442
|
+
// CommonJS/npm, we want to export Box instead of assigning to global Window
|
443
|
+
module.exports = Box;
|
444
|
+
} else {
|
445
|
+
// Make sure not to override Box namespace
|
446
|
+
window.Box = window.Box || {};
|
447
|
+
|
448
|
+
// Copy all properties onto namespace (ES3 safe for loop)
|
449
|
+
for (var key in Box) {
|
450
|
+
if (Box.hasOwnProperty(key)) {
|
451
|
+
window.Box[key] = Box[key];
|
452
|
+
}
|
453
|
+
}
|
454
|
+
}
|
455
|
+
|
456
|
+
// Potentially window is not defined yet, so bind to 'this' instead
|
457
|
+
}(typeof window !== 'undefined' ? window : this));
|
458
|
+
// End Wrapper
|
459
|
+
|