wat_catcher 0.6.0 → 0.7.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 +4 -4
- data/app/controllers/wat_catcher/bugsnag_controller.rb +26 -0
- data/app/controllers/wat_catcher/wats_controller.rb +1 -1
- data/config/routes.rb +4 -1
- data/lib/wat_catcher.rb +1 -0
- data/lib/wat_catcher/version.rb +1 -1
- data/lib/wat_catcher/wattle_helper.rb +10 -1
- data/spec/ci.sh +8 -0
- data/spec/controllers/bugsnag_controller_spec.rb +33 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +23 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/spec_helper.rb +63 -0
- data/vendor/assets/javascripts/bugsnag.js +623 -0
- data/wat_catcher.gemspec +5 -0
- metadata +142 -2
@@ -0,0 +1,36 @@
|
|
1
|
+
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
4
|
+
# The test environment is used exclusively to run your application's
|
5
|
+
# test suite. You never need to work with it otherwise. Remember that
|
6
|
+
# your test database is "scratch space" for the test suite and is wiped
|
7
|
+
# and recreated between test runs. Don't rely on the data there!
|
8
|
+
config.cache_classes = true
|
9
|
+
|
10
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
11
|
+
# just for the purpose of running a single test. If you are using a tool that
|
12
|
+
# preloads Rails for running tests, you may have to set it to true.
|
13
|
+
config.eager_load = false
|
14
|
+
|
15
|
+
# Configure static asset server for tests with Cache-Control for performance.
|
16
|
+
config.serve_static_assets = true
|
17
|
+
config.static_cache_control = "public, max-age=3600"
|
18
|
+
|
19
|
+
# Show full error reports and disable caching.
|
20
|
+
config.consider_all_requests_local = true
|
21
|
+
config.action_controller.perform_caching = false
|
22
|
+
|
23
|
+
# Raise exceptions instead of rendering exception templates.
|
24
|
+
config.action_dispatch.show_exceptions = false
|
25
|
+
|
26
|
+
# Disable request forgery protection in test environment.
|
27
|
+
config.action_controller.allow_forgery_protection = false
|
28
|
+
|
29
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
30
|
+
# The :test delivery method accumulates sent emails in the
|
31
|
+
# ActionMailer::Base.deliveries array.
|
32
|
+
config.action_mailer.delivery_method = :test
|
33
|
+
|
34
|
+
# Print deprecation notices to the stderr.
|
35
|
+
config.active_support.deprecation = :stderr
|
36
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
4
|
+
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
5
|
+
|
6
|
+
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
|
7
|
+
# Rails.backtrace_cleaner.remove_silencers!
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Add new inflection rules using the following format. Inflections
|
4
|
+
# are locale specific, and you may define rules for as many different
|
5
|
+
# locales as you wish. All of these examples are active by default:
|
6
|
+
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
7
|
+
# inflect.plural /^(ox)$/i, '\1en'
|
8
|
+
# inflect.singular /^(ox)en/i, '\1'
|
9
|
+
# inflect.irregular 'person', 'people'
|
10
|
+
# inflect.uncountable %w( fish sheep )
|
11
|
+
# end
|
12
|
+
|
13
|
+
# These inflection rules are supported but not enabled by default:
|
14
|
+
# ActiveSupport::Inflector.inflections(:en) do |inflect|
|
15
|
+
# inflect.acronym 'RESTful'
|
16
|
+
# end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Your secret key is used for verifying the integrity of signed cookies.
|
4
|
+
# If you change this key, all old signed cookies will become invalid!
|
5
|
+
|
6
|
+
# Make sure the secret is at least 30 characters and all random,
|
7
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
8
|
+
# You can use `rake secret` to generate a secure secret key.
|
9
|
+
|
10
|
+
# Make sure your secret_key_base is kept private
|
11
|
+
# if you're sharing your code publicly.
|
12
|
+
Dummy::Application.config.secret_key_base = 'ef82b8f94b465ceaa4347d1b02383a96b23cceb8676384a0012dd23c8d81ead2a396adcc47773088fd089674c03ad7828835318f2826699d3f12686d343a75e8'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# This file contains settings for ActionController::ParamsWrapper which
|
4
|
+
# is enabled by default.
|
5
|
+
|
6
|
+
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
7
|
+
ActiveSupport.on_load(:action_controller) do
|
8
|
+
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
|
9
|
+
end
|
10
|
+
|
11
|
+
# To enable root element in JSON for ActiveRecord objects.
|
12
|
+
# ActiveSupport.on_load(:active_record) do
|
13
|
+
# self.include_root_in_json = true
|
14
|
+
# end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Files in the config/locales directory are used for internationalization
|
2
|
+
# and are automatically loaded by Rails. If you want to use locales other
|
3
|
+
# than English, add the necessary files in this directory.
|
4
|
+
#
|
5
|
+
# To use the locales, use `I18n.t`:
|
6
|
+
#
|
7
|
+
# I18n.t 'hello'
|
8
|
+
#
|
9
|
+
# In views, this is aliased to just `t`:
|
10
|
+
#
|
11
|
+
# <%= t('hello') %>
|
12
|
+
#
|
13
|
+
# To use a different locale, set it with `I18n.locale`:
|
14
|
+
#
|
15
|
+
# I18n.locale = :es
|
16
|
+
#
|
17
|
+
# This would use the information in config/locales/es.yml.
|
18
|
+
#
|
19
|
+
# To learn more, please read the Rails Internationalization guide
|
20
|
+
# available at http://guides.rubyonrails.org/i18n.html.
|
21
|
+
|
22
|
+
en:
|
23
|
+
hello: "Hello world"
|
File without changes
|
File without changes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/404.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
54
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
55
|
+
</div>
|
56
|
+
<p>If you are the application owner check the logs for more information.</p>
|
57
|
+
</body>
|
58
|
+
</html>
|
@@ -0,0 +1,58 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/422.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>The change you wanted was rejected.</h1>
|
54
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
55
|
+
</div>
|
56
|
+
<p>If you are the application owner check the logs for more information.</p>
|
57
|
+
</body>
|
58
|
+
</html>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
background-color: #EFEFEF;
|
8
|
+
color: #2E2F30;
|
9
|
+
text-align: center;
|
10
|
+
font-family: arial, sans-serif;
|
11
|
+
}
|
12
|
+
|
13
|
+
div.dialog {
|
14
|
+
width: 25em;
|
15
|
+
margin: 4em auto 0 auto;
|
16
|
+
border: 1px solid #CCC;
|
17
|
+
border-right-color: #999;
|
18
|
+
border-left-color: #999;
|
19
|
+
border-bottom-color: #BBB;
|
20
|
+
border-top: #B00100 solid 4px;
|
21
|
+
border-top-left-radius: 9px;
|
22
|
+
border-top-right-radius: 9px;
|
23
|
+
background-color: white;
|
24
|
+
padding: 7px 4em 0 4em;
|
25
|
+
}
|
26
|
+
|
27
|
+
h1 {
|
28
|
+
font-size: 100%;
|
29
|
+
color: #730E15;
|
30
|
+
line-height: 1.5em;
|
31
|
+
}
|
32
|
+
|
33
|
+
body > p {
|
34
|
+
width: 33em;
|
35
|
+
margin: 0 auto 1em;
|
36
|
+
padding: 1em 0;
|
37
|
+
background-color: #F7F7F7;
|
38
|
+
border: 1px solid #CCC;
|
39
|
+
border-right-color: #999;
|
40
|
+
border-bottom-color: #999;
|
41
|
+
border-bottom-left-radius: 4px;
|
42
|
+
border-bottom-right-radius: 4px;
|
43
|
+
border-top-color: #DADADA;
|
44
|
+
color: #666;
|
45
|
+
box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
</head>
|
49
|
+
|
50
|
+
<body>
|
51
|
+
<!-- This file lives in public/500.html -->
|
52
|
+
<div class="dialog">
|
53
|
+
<h1>We're sorry, but something went wrong.</h1>
|
54
|
+
</div>
|
55
|
+
<p>If you are the application owner check the logs for more information.</p>
|
56
|
+
</body>
|
57
|
+
</html>
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
2
|
+
ENV["RAILS_ENV"] ||= 'test'
|
3
|
+
|
4
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
5
|
+
|
6
|
+
require 'rspec/rails'
|
7
|
+
require 'rspec/autorun'
|
8
|
+
#require 'rr'
|
9
|
+
require 'sidekiq/testing/inline'
|
10
|
+
|
11
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
12
|
+
# in spec/support/ and its subdirectories.
|
13
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
14
|
+
|
15
|
+
Sidekiq::Testing.fake!
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
|
19
|
+
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
20
|
+
# examples within a transaction, remove the following line or assign false
|
21
|
+
# instead of true.
|
22
|
+
#config.use_transactional_fixtures = false
|
23
|
+
|
24
|
+
#config.before(:suite) do
|
25
|
+
# DatabaseCleaner.strategy = :transaction
|
26
|
+
#end
|
27
|
+
#
|
28
|
+
#config.before(:each) do
|
29
|
+
# DatabaseCleaner.start
|
30
|
+
#end
|
31
|
+
#
|
32
|
+
#config.after(:each) do
|
33
|
+
# DatabaseCleaner.clean
|
34
|
+
#end
|
35
|
+
|
36
|
+
# ## Mock Framework
|
37
|
+
#
|
38
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
39
|
+
#
|
40
|
+
# config.mock_with :mocha
|
41
|
+
# config.mock_with :flexmock
|
42
|
+
# config.mock_with :rr
|
43
|
+
|
44
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
45
|
+
config.fixture_path = "#{::Rails.root}/spec/fixtures"
|
46
|
+
|
47
|
+
|
48
|
+
# If true, the base class of anonymous controllers will be inferred
|
49
|
+
# automatically. This will be the default behavior in future versions of
|
50
|
+
# rspec-rails.
|
51
|
+
config.infer_base_class_for_anonymous_controllers = false
|
52
|
+
config.global_fixtures = :all
|
53
|
+
|
54
|
+
# Run specs in random order to surface order dependencies. If you find an
|
55
|
+
# order dependency and want to debug it, you can fix the order by providing
|
56
|
+
# the seed, which is printed after each run.
|
57
|
+
# --seed 1234
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
config.order = "random"
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,623 @@
|
|
1
|
+
//
|
2
|
+
// **Bugsnag.js** is the official JavaScript notifier for
|
3
|
+
// [Bugsnag](https://bugsnag.com).
|
4
|
+
//
|
5
|
+
// Bugsnag gives you instant notification of errors and
|
6
|
+
// exceptions in your website's JavaScript code.
|
7
|
+
//
|
8
|
+
// Bugsnag.js is incredibly small, and has no external dependencies (not even
|
9
|
+
// jQuery!) so you can safely use it on any website.
|
10
|
+
//
|
11
|
+
|
12
|
+
// The `Bugsnag` object is the only globally exported variable
|
13
|
+
(function(definition) {
|
14
|
+
var old = window.Bugsnag;
|
15
|
+
window.Bugsnag = definition(window, document, navigator, old);
|
16
|
+
})(function (window, document, navigator, old) {
|
17
|
+
var self = {},
|
18
|
+
lastEvent,
|
19
|
+
lastScript,
|
20
|
+
previousNotification,
|
21
|
+
shouldCatch = true,
|
22
|
+
ignoreOnError = 0,
|
23
|
+
|
24
|
+
// We've seen cases where individual clients can infinite loop sending us errors
|
25
|
+
// (in some cases 10,000+ errors per page). This limit is at the point where
|
26
|
+
// you've probably learned everything useful there is to debug the problem,
|
27
|
+
// and we're happy to under-estimate the count to save the client (and Bugsnag's) resources.
|
28
|
+
eventsRemaining = 10;
|
29
|
+
|
30
|
+
self.noConflict = function() {
|
31
|
+
window.Bugsnag = old;
|
32
|
+
return self;
|
33
|
+
};
|
34
|
+
|
35
|
+
//
|
36
|
+
// ### Manual error notification (public methods)
|
37
|
+
//
|
38
|
+
|
39
|
+
// #### Bugsnag.notifyException
|
40
|
+
//
|
41
|
+
// Notify Bugsnag about a given `exception`, typically that you've caught
|
42
|
+
// with a `try/catch` statement or that you've generated yourself.
|
43
|
+
//
|
44
|
+
// It's almost always better to let an exception bubble rather than catching
|
45
|
+
// it, as that gives more consistent behaviour across browsers. Consider
|
46
|
+
// re-throwing instead of calling .notifyException.
|
47
|
+
//
|
48
|
+
// Since most JavaScript exceptions use the `Error` class, we also allow
|
49
|
+
// you to provide a custom error name when calling `notifyException`.
|
50
|
+
//
|
51
|
+
// You should never pass severity. It's there for internal use, so we
|
52
|
+
// can mark uncaught exceptions as "fatal". The default value is "error"
|
53
|
+
// and "warning" is also supported by the backend, all other values cause
|
54
|
+
// the notification to be dropped; and you will not see it in your dashboard.
|
55
|
+
self.notifyException = function (exception, name, metaData, severity) {
|
56
|
+
if (name && typeof name !== "string") {
|
57
|
+
metaData = name;
|
58
|
+
}
|
59
|
+
if (!metaData) {
|
60
|
+
metaData = {};
|
61
|
+
}
|
62
|
+
addScriptToMetaData(metaData);
|
63
|
+
|
64
|
+
sendToBugsnag({
|
65
|
+
name: name || exception.name,
|
66
|
+
message: exception.message || exception.description,
|
67
|
+
stacktrace: stacktraceFromException(exception) || generateStacktrace(),
|
68
|
+
file: exception.fileName || exception.sourceURL,
|
69
|
+
lineNumber: exception.lineNumber || exception.line,
|
70
|
+
columnNumber: exception.columnNumber ? exception.columnNumber + 1 : undefined,
|
71
|
+
severity: severity || "error"
|
72
|
+
}, metaData);
|
73
|
+
};
|
74
|
+
|
75
|
+
// #### Bugsnag.notify
|
76
|
+
//
|
77
|
+
// Notify Bugsnag about an error by passing in a `name` and `message`,
|
78
|
+
// without requiring an exception.
|
79
|
+
self.notify = function (name, message, metaData) {
|
80
|
+
sendToBugsnag({
|
81
|
+
name: name,
|
82
|
+
message: message,
|
83
|
+
stacktrace: generateStacktrace(),
|
84
|
+
severity: "error"
|
85
|
+
}, metaData);
|
86
|
+
};
|
87
|
+
|
88
|
+
// Return a function acts like the given function, but reports
|
89
|
+
// any exceptions to Bugsnag before re-throwing them.
|
90
|
+
//
|
91
|
+
// This is not a public function because it can only be used if
|
92
|
+
// the exception is not caught after being thrown out of this function.
|
93
|
+
//
|
94
|
+
// If you call wrap twice on the same function, it'll give you back the
|
95
|
+
// same wrapped function. This lets removeEventListener to continue to
|
96
|
+
// work.
|
97
|
+
function wrap(_super, options) {
|
98
|
+
try {
|
99
|
+
if (typeof _super !== "function") {
|
100
|
+
return _super;
|
101
|
+
}
|
102
|
+
if (!_super.bugsnag) {
|
103
|
+
var currentScript = getCurrentScript();
|
104
|
+
_super.bugsnag = function (event) {
|
105
|
+
if (options && options.eventHandler) {
|
106
|
+
lastEvent = event;
|
107
|
+
}
|
108
|
+
lastScript = currentScript;
|
109
|
+
|
110
|
+
// We set shouldCatch to false on IE < 10 because catching the error ruins the file/line as reported in window.onerror,
|
111
|
+
// We set shouldCatch to false on Chrome/Safari because it interferes with "break on unhandled exception"
|
112
|
+
// All other browsers need shouldCatch to be true, as they don't pass the exception object to window.onerror
|
113
|
+
if (shouldCatch) {
|
114
|
+
try {
|
115
|
+
return _super.apply(this, arguments);
|
116
|
+
} catch (e) {
|
117
|
+
// We do this rather than stashing treating the error like lastEvent
|
118
|
+
// because in FF 26 onerror is not called for synthesized event handlers.
|
119
|
+
if (getSetting("autoNotify", true)) {
|
120
|
+
self.notifyException(e, null, null, "fatal");
|
121
|
+
ignoreNextOnError();
|
122
|
+
}
|
123
|
+
throw e;
|
124
|
+
} finally {
|
125
|
+
lastScript = null;
|
126
|
+
}
|
127
|
+
} else {
|
128
|
+
var ret = _super.apply(this, arguments);
|
129
|
+
// in case of error, this is set to null in window.onerror
|
130
|
+
lastScript = null;
|
131
|
+
return ret;
|
132
|
+
}
|
133
|
+
};
|
134
|
+
_super.bugsnag.bugsnag = _super.bugsnag;
|
135
|
+
}
|
136
|
+
return _super.bugsnag;
|
137
|
+
|
138
|
+
// This can happen if _super is not a normal javascript function.
|
139
|
+
// For example, see https://github.com/bugsnag/bugsnag-js/issues/28
|
140
|
+
} catch (e) {
|
141
|
+
return _super;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
//
|
146
|
+
// ### Script tag tracking
|
147
|
+
//
|
148
|
+
|
149
|
+
// To emulate document.currentScript we use document.scripts.last.
|
150
|
+
// This only works while synchronous scripts are running, so we track
|
151
|
+
// that here.
|
152
|
+
var synchronousScriptsRunning = document.readyState !== "complete";
|
153
|
+
function loadCompleted() {
|
154
|
+
synchronousScriptsRunning = false;
|
155
|
+
}
|
156
|
+
|
157
|
+
// from jQuery. We don't have quite such tight bounds as they do if
|
158
|
+
// we end up on the window.onload event as we don't try and hack
|
159
|
+
// the .scrollLeft() fix in because it doesn't work in frames so
|
160
|
+
// we'd need these fallbacks anyway.
|
161
|
+
// The worst that can happen is we group an event handler that fires
|
162
|
+
// before us into the last script tag.
|
163
|
+
if (document.addEventListener) {
|
164
|
+
document.addEventListener("DOMContentLoaded", loadCompleted, true);
|
165
|
+
window.addEventListener("load", loadCompleted, true);
|
166
|
+
} else {
|
167
|
+
window.attachEvent("onload", loadCompleted);
|
168
|
+
}
|
169
|
+
|
170
|
+
function getCurrentScript() {
|
171
|
+
var script = document.currentScript || lastScript;
|
172
|
+
|
173
|
+
if (!script && synchronousScriptsRunning) {
|
174
|
+
var scripts = document.getElementsByTagName("script");
|
175
|
+
script = scripts[scripts.length - 1];
|
176
|
+
}
|
177
|
+
|
178
|
+
return script;
|
179
|
+
}
|
180
|
+
|
181
|
+
function addScriptToMetaData(metaData) {
|
182
|
+
var script = getCurrentScript();
|
183
|
+
|
184
|
+
if (script) {
|
185
|
+
metaData.script = {
|
186
|
+
src: script.src,
|
187
|
+
content: getSetting("inlineScript", true) ? script.innerHTML : ""
|
188
|
+
};
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
//
|
193
|
+
// ### Helpers & Setup
|
194
|
+
//
|
195
|
+
|
196
|
+
// Compile regular expressions upfront.
|
197
|
+
var API_KEY_REGEX = /^[0-9a-f]{32}$/i;
|
198
|
+
var FUNCTION_REGEX = /function\s*([\w\-$]+)?\s*\(/i;
|
199
|
+
|
200
|
+
// Set up default notifier settings.
|
201
|
+
var DEFAULT_BASE_ENDPOINT = "https://notify.bugsnag.com/";
|
202
|
+
var DEFAULT_NOTIFIER_ENDPOINT = DEFAULT_BASE_ENDPOINT + "js";
|
203
|
+
var NOTIFIER_VERSION = "2.3.2";
|
204
|
+
|
205
|
+
// Keep a reference to the currently executing script in the DOM.
|
206
|
+
// We'll use this later to extract settings from attributes.
|
207
|
+
var scripts = document.getElementsByTagName("script");
|
208
|
+
var thisScript = scripts[scripts.length - 1];
|
209
|
+
|
210
|
+
// Simple logging function that wraps `console.log` if available.
|
211
|
+
// This is useful for warning about configuration issues
|
212
|
+
// eg. forgetting to set an API key.
|
213
|
+
function log(msg) {
|
214
|
+
var console = window.console;
|
215
|
+
if (console !== undefined && console.log !== undefined) {
|
216
|
+
console.log("[Bugsnag] " + msg);
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
// Deeply serialize an object into a query string. We use the PHP-style
|
221
|
+
// nested object syntax, `nested[keys]=val`, to support heirachical
|
222
|
+
// objects. Similar to jQuery's `$.param` method.
|
223
|
+
function serialize(obj, prefix) {
|
224
|
+
var str = [];
|
225
|
+
for (var p in obj) {
|
226
|
+
if (obj.hasOwnProperty(p) && p != null && obj[p] != null) {
|
227
|
+
var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
|
228
|
+
str.push(typeof v === "object" ? serialize(v, k) : encodeURIComponent(k) + "=" + encodeURIComponent(v));
|
229
|
+
}
|
230
|
+
}
|
231
|
+
return str.join("&");
|
232
|
+
}
|
233
|
+
|
234
|
+
// Deep-merge the `source` object into the `target` object and return
|
235
|
+
// the `target`. Properties in source that will overwrite those in target.
|
236
|
+
// Similar to jQuery's `$.extend` method.
|
237
|
+
function merge(target, source) {
|
238
|
+
if (source == null) {
|
239
|
+
return target;
|
240
|
+
}
|
241
|
+
|
242
|
+
target = target || {};
|
243
|
+
for (var key in source) {
|
244
|
+
if (source.hasOwnProperty(key)) {
|
245
|
+
try {
|
246
|
+
if (source[key].constructor === Object) {
|
247
|
+
target[key] = merge(target[key], source[key]);
|
248
|
+
} else {
|
249
|
+
target[key] = source[key];
|
250
|
+
}
|
251
|
+
} catch (e) {
|
252
|
+
target[key] = source[key];
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
return target;
|
258
|
+
}
|
259
|
+
|
260
|
+
// Make a HTTP request with given `url` and `params` object.
|
261
|
+
// For maximum browser compatibility and cross-domain support, requests are
|
262
|
+
// made by creating a temporary JavaScript `Image` object.
|
263
|
+
function request(url, params) {
|
264
|
+
if (typeof BUGSNAG_TESTING !== "undefined" && self.testRequest) {
|
265
|
+
self.testRequest(url, params);
|
266
|
+
} else {
|
267
|
+
var img = new Image();
|
268
|
+
img.src = url + "?" + serialize(params) + "&ct=img&cb=" + new Date().getTime();
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
// Extract all `data-*` attributes from a DOM element and return them as an
|
273
|
+
// object. This is used to allow Bugsnag settings to be set via attributes
|
274
|
+
// on the `script` tag, eg. `<script data-apikey="xyz">`.
|
275
|
+
// Similar to jQuery's `$(el).data()` method.
|
276
|
+
function getData(node) {
|
277
|
+
var dataAttrs = {};
|
278
|
+
var dataRegex = /^data\-([\w\-]+)$/;
|
279
|
+
var attrs = node.attributes;
|
280
|
+
for (var i = 0; i < attrs.length; i++) {
|
281
|
+
var attr = attrs[i];
|
282
|
+
if (dataRegex.test(attr.nodeName)) {
|
283
|
+
var key = attr.nodeName.match(dataRegex)[1];
|
284
|
+
dataAttrs[key] = attr.nodeValue;
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
return dataAttrs;
|
289
|
+
}
|
290
|
+
|
291
|
+
// Get configuration settings from either `self` (the `Bugsnag` object)
|
292
|
+
// or `data` (the `data-*` attributes).
|
293
|
+
var data;
|
294
|
+
function getSetting(name, fallback) {
|
295
|
+
data = data || getData(thisScript);
|
296
|
+
var setting = self[name] !== undefined ? self[name] : data[name.toLowerCase()];
|
297
|
+
if (setting === "false") {
|
298
|
+
setting = false;
|
299
|
+
}
|
300
|
+
return setting !== undefined ? setting : fallback;
|
301
|
+
}
|
302
|
+
|
303
|
+
// Validate a Bugsnag API key exists and is of the correct format.
|
304
|
+
function validateApiKey(apiKey) {
|
305
|
+
if (apiKey == null || !apiKey.match(API_KEY_REGEX)) {
|
306
|
+
log("Invalid API key '" + apiKey + "'");
|
307
|
+
return false;
|
308
|
+
}
|
309
|
+
|
310
|
+
return true;
|
311
|
+
}
|
312
|
+
|
313
|
+
// Send an error to Bugsnag.
|
314
|
+
function sendToBugsnag(details, metaData) {
|
315
|
+
// Validate the configured API key.
|
316
|
+
var apiKey = getSetting("apiKey");
|
317
|
+
if (!validateApiKey(apiKey) || !eventsRemaining) {
|
318
|
+
return;
|
319
|
+
}
|
320
|
+
eventsRemaining -= 1;
|
321
|
+
|
322
|
+
// Check if we should notify for this release stage.
|
323
|
+
var releaseStage = getSetting("releaseStage");
|
324
|
+
var notifyReleaseStages = getSetting("notifyReleaseStages");
|
325
|
+
if (notifyReleaseStages) {
|
326
|
+
var shouldNotify = false;
|
327
|
+
for (var i = 0; i < notifyReleaseStages.length; i++) {
|
328
|
+
if (releaseStage === notifyReleaseStages[i]) {
|
329
|
+
shouldNotify = true;
|
330
|
+
break;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
if (!shouldNotify) {
|
335
|
+
return;
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|
339
|
+
// Don't send multiple copies of the same error.
|
340
|
+
// This fixes a problem when a client goes into an infinite loop,
|
341
|
+
// and starts wasting all their bandwidth sending messages to bugsnag.
|
342
|
+
var deduplicate = [details.name, details.message, details.stacktrace].join("|");
|
343
|
+
if (deduplicate === previousNotification) {
|
344
|
+
return;
|
345
|
+
} else {
|
346
|
+
previousNotification = deduplicate;
|
347
|
+
}
|
348
|
+
|
349
|
+
if (lastEvent) {
|
350
|
+
metaData = metaData || {};
|
351
|
+
metaData["Last Event"] = eventToMetaData(lastEvent);
|
352
|
+
}
|
353
|
+
|
354
|
+
// Merge the local and global `metaData`.
|
355
|
+
var mergedMetaData = merge(merge({}, getSetting("metaData")), metaData);
|
356
|
+
|
357
|
+
// Run any `beforeNotify` function
|
358
|
+
var beforeNotify = self.beforeNotify;
|
359
|
+
if (typeof(beforeNotify) === "function") {
|
360
|
+
var retVal = beforeNotify(details, mergedMetaData);
|
361
|
+
if (retVal === false) {
|
362
|
+
return;
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
// Make the request:
|
367
|
+
//
|
368
|
+
// - Work out which endpoint to send to.
|
369
|
+
// - Combine error information with other data such as
|
370
|
+
// user-agent and locale, `metaData` and settings.
|
371
|
+
// - Make the HTTP request.
|
372
|
+
var location = window.location;
|
373
|
+
console.log(getSetting("endpoint"));
|
374
|
+
request(getSetting("endpoint") || DEFAULT_NOTIFIER_ENDPOINT, {
|
375
|
+
notifierVersion: NOTIFIER_VERSION,
|
376
|
+
|
377
|
+
apiKey: apiKey,
|
378
|
+
projectRoot: getSetting("projectRoot") || location.protocol + "//" + location.host,
|
379
|
+
context: getSetting("context") || location.pathname,
|
380
|
+
userId: getSetting("userId"), // Deprecated, remove in v3
|
381
|
+
user: getSetting("user"),
|
382
|
+
metaData: mergedMetaData,
|
383
|
+
releaseStage: releaseStage,
|
384
|
+
appVersion: getSetting("appVersion"),
|
385
|
+
|
386
|
+
url: window.location.href,
|
387
|
+
userAgent: navigator.userAgent,
|
388
|
+
language: navigator.language || navigator.userLanguage,
|
389
|
+
|
390
|
+
severity: details.severity,
|
391
|
+
|
392
|
+
name: details.name,
|
393
|
+
message: details.message,
|
394
|
+
stacktrace: details.stacktrace,
|
395
|
+
file: details.file,
|
396
|
+
lineNumber: details.lineNumber,
|
397
|
+
columnNumber: details.columnNumber
|
398
|
+
});
|
399
|
+
}
|
400
|
+
|
401
|
+
// Generate a browser stacktrace (or approximation) from the current stack.
|
402
|
+
// This is used to add a stacktrace to `Bugsnag.notify` calls, and to add a
|
403
|
+
// stacktrace approximation where we can't get one from an exception.
|
404
|
+
function generateStacktrace() {
|
405
|
+
var stacktrace;
|
406
|
+
var MAX_FAKE_STACK_SIZE = 10;
|
407
|
+
var ANONYMOUS_FUNCTION_PLACEHOLDER = "[anonymous]";
|
408
|
+
|
409
|
+
// Try to generate a real stacktrace (most browsers, except IE9 and below).
|
410
|
+
try {
|
411
|
+
throw new Error("");
|
412
|
+
} catch (exception) {
|
413
|
+
stacktrace = stacktraceFromException(exception);
|
414
|
+
}
|
415
|
+
|
416
|
+
// Otherwise, build a fake stacktrace from the list of method names by
|
417
|
+
// looping through the list of functions that called this one (and skip
|
418
|
+
// whoever called us).
|
419
|
+
if (!stacktrace) {
|
420
|
+
var functionStack = [];
|
421
|
+
try {
|
422
|
+
var curr = arguments.callee.caller.caller;
|
423
|
+
while (curr && functionStack.length < MAX_FAKE_STACK_SIZE) {
|
424
|
+
var fn = FUNCTION_REGEX.test(curr.toString()) ? RegExp.$1 || ANONYMOUS_FUNCTION_PLACEHOLDER : ANONYMOUS_FUNCTION_PLACEHOLDER;
|
425
|
+
functionStack.push(fn);
|
426
|
+
curr = curr.caller;
|
427
|
+
}
|
428
|
+
} catch (e) {
|
429
|
+
log(e);
|
430
|
+
|
431
|
+
}
|
432
|
+
|
433
|
+
stacktrace = functionStack.join("\n");
|
434
|
+
}
|
435
|
+
|
436
|
+
// Tell the backend to ignore the first two lines in the stack-trace.
|
437
|
+
// generateStacktrace() + window.onerror,
|
438
|
+
// generateStacktrace() + notify,
|
439
|
+
// generateStacktrace() + notifyException
|
440
|
+
return "<generated>\n" + stacktrace;
|
441
|
+
}
|
442
|
+
|
443
|
+
// Get the stacktrace string from an exception
|
444
|
+
function stacktraceFromException(exception) {
|
445
|
+
return exception.stack || exception.backtrace || exception.stacktrace;
|
446
|
+
}
|
447
|
+
|
448
|
+
// Populate the event tab of meta-data.
|
449
|
+
function eventToMetaData(event) {
|
450
|
+
var tab = {
|
451
|
+
millisecondsAgo: new Date() - event.timeStamp,
|
452
|
+
type: event.type,
|
453
|
+
which: event.which,
|
454
|
+
target: targetToString(event.target)
|
455
|
+
};
|
456
|
+
|
457
|
+
return tab;
|
458
|
+
}
|
459
|
+
|
460
|
+
// Convert a DOM element into a string suitable for passing to Bugsnag.
|
461
|
+
function targetToString(target) {
|
462
|
+
if (target) {
|
463
|
+
var attrs = target.attributes;
|
464
|
+
|
465
|
+
if (attrs) {
|
466
|
+
var ret = "<" + target.nodeName.toLowerCase();
|
467
|
+
for (var i = 0; i < attrs.length; i++) {
|
468
|
+
if (attrs[i].value && attrs[i].value.toString() != "null") {
|
469
|
+
ret += " " + attrs[i].name + "=\"" + attrs[i].value + "\"";
|
470
|
+
}
|
471
|
+
}
|
472
|
+
return ret + ">";
|
473
|
+
} else {
|
474
|
+
// e.g. #document
|
475
|
+
return target.nodeName;
|
476
|
+
}
|
477
|
+
}
|
478
|
+
}
|
479
|
+
|
480
|
+
// If we've notified bugsnag of an exception in wrap, we don't want to
|
481
|
+
// re-notify when it hits window.onerror after we re-throw it.
|
482
|
+
function ignoreNextOnError() {
|
483
|
+
ignoreOnError += 1;
|
484
|
+
window.setTimeout(function () {
|
485
|
+
ignoreOnError -= 1;
|
486
|
+
});
|
487
|
+
}
|
488
|
+
|
489
|
+
// Disable catching on IE < 10 as it destroys stack-traces from generateStackTrace()
|
490
|
+
if (!window.atob) {
|
491
|
+
shouldCatch = false;
|
492
|
+
|
493
|
+
// Disable catching on browsers that support HTML5 ErrorEvents properly.
|
494
|
+
// This lets debug on unhandled exceptions work.
|
495
|
+
} else if (window.ErrorEvent) {
|
496
|
+
try {
|
497
|
+
if (new window.ErrorEvent("test").colno === 0) {
|
498
|
+
shouldCatch = false;
|
499
|
+
}
|
500
|
+
} catch(e){ }
|
501
|
+
}
|
502
|
+
|
503
|
+
|
504
|
+
//
|
505
|
+
// ### Polyfilling
|
506
|
+
//
|
507
|
+
|
508
|
+
// Add a polyFill to an object
|
509
|
+
function polyFill(obj, name, makeReplacement) {
|
510
|
+
var original = obj[name];
|
511
|
+
var replacement = makeReplacement(original);
|
512
|
+
obj[name] = replacement;
|
513
|
+
|
514
|
+
if (typeof BUGSNAG_TESTING !== "undefined" && window.undo) {
|
515
|
+
window.undo.push(function () {
|
516
|
+
obj[name] = original;
|
517
|
+
});
|
518
|
+
}
|
519
|
+
}
|
520
|
+
|
521
|
+
if (getSetting("autoNotify", true)) {
|
522
|
+
//
|
523
|
+
// ### Automatic error notification
|
524
|
+
//
|
525
|
+
// Attach to `window.onerror` events and notify Bugsnag when they happen.
|
526
|
+
// These are mostly js compile/parse errors, but on some browsers all
|
527
|
+
// "uncaught" exceptions will fire this event.
|
528
|
+
//
|
529
|
+
polyFill(window, "onerror", function (_super) {
|
530
|
+
// Keep a reference to any existing `window.onerror` handler
|
531
|
+
if (typeof BUGSNAG_TESTING !== "undefined") {
|
532
|
+
self._onerror = _super;
|
533
|
+
}
|
534
|
+
|
535
|
+
return function bugsnag(message, url, lineNo, charNo, exception) {
|
536
|
+
var shouldNotify = getSetting("autoNotify", true);
|
537
|
+
var metaData = {};
|
538
|
+
|
539
|
+
// IE 6+ support.
|
540
|
+
if (!charNo && window.event) {
|
541
|
+
charNo = window.event.errorCharacter;
|
542
|
+
}
|
543
|
+
|
544
|
+
addScriptToMetaData(metaData);
|
545
|
+
lastScript = null;
|
546
|
+
|
547
|
+
if (shouldNotify && !ignoreOnError) {
|
548
|
+
|
549
|
+
sendToBugsnag({
|
550
|
+
name: exception && exception.name || "window.onerror",
|
551
|
+
message: message,
|
552
|
+
file: url,
|
553
|
+
lineNumber: lineNo,
|
554
|
+
columnNumber: charNo,
|
555
|
+
stacktrace: (exception && stacktraceFromException(exception)) || generateStacktrace(),
|
556
|
+
severity: "fatal"
|
557
|
+
}, metaData);
|
558
|
+
}
|
559
|
+
|
560
|
+
if (typeof BUGSNAG_TESTING !== "undefined") {
|
561
|
+
_super = self._onerror;
|
562
|
+
}
|
563
|
+
|
564
|
+
// Fire the existing `window.onerror` handler, if one exists
|
565
|
+
if (_super) {
|
566
|
+
_super(message, url, lineNo, charNo, exception);
|
567
|
+
}
|
568
|
+
};
|
569
|
+
});
|
570
|
+
|
571
|
+
var hijackTimeFunc = function (_super) {
|
572
|
+
// Note, we don't do `_super.call` because that doesn't work on IE 8,
|
573
|
+
// luckily this is implicitly window so it just works everywhere.
|
574
|
+
//
|
575
|
+
// setTimout in all browsers except IE <9 allows additional parameters
|
576
|
+
// to be passed, so in order to support these without resorting to call/apply
|
577
|
+
// we need an extra layer of wrapping.
|
578
|
+
return function (f, t) {
|
579
|
+
if (typeof f === "function") {
|
580
|
+
f = wrap(f);
|
581
|
+
var args = Array.prototype.slice.call(arguments, 2);
|
582
|
+
return _super(function () {
|
583
|
+
f.apply(this, args);
|
584
|
+
}, t);
|
585
|
+
} else {
|
586
|
+
return _super(f, t);
|
587
|
+
}
|
588
|
+
};
|
589
|
+
};
|
590
|
+
|
591
|
+
polyFill(window, "setTimeout", hijackTimeFunc);
|
592
|
+
polyFill(window, "setInterval", hijackTimeFunc);
|
593
|
+
if (window.requestAnimationFrame) {
|
594
|
+
polyFill(window, "requestAnimationFrame", hijackTimeFunc);
|
595
|
+
}
|
596
|
+
|
597
|
+
var hijackEventFunc = function (_super) {
|
598
|
+
return function (e, f, capture, secure) {
|
599
|
+
// HTML lets event-handlers be objects with a handlEvent function,
|
600
|
+
// we need to change f.handleEvent here, as self.wrap will ignore f.
|
601
|
+
if (f && f.handleEvent) {
|
602
|
+
f.handleEvent = wrap(f.handleEvent, {eventHandler: true});
|
603
|
+
}
|
604
|
+
return _super.call(this, e, wrap(f, {eventHandler: true}), capture, secure);
|
605
|
+
};
|
606
|
+
};
|
607
|
+
|
608
|
+
// EventTarget is all that's required in modern chrome/opera
|
609
|
+
// EventTarget + Window + ModalWindow is all that's required in modern FF (there are a few Moz prefixed ones that we're ignoring)
|
610
|
+
// The rest is a collection of stuff for Safari and IE 11. (Again ignoring a few MS and WebKit prefixed things)
|
611
|
+
"EventTarget Window Node ApplicationCache AudioTrackList ChannelMergerNode CryptoOperation EventSource FileReader HTMLUnknownElement IDBDatabase IDBRequest IDBTransaction KeyOperation MediaController MessagePort ModalWindow Notification SVGElementInstance Screen TextTrack TextTrackCue TextTrackList WebSocket WebSocketWorker Worker XMLHttpRequest XMLHttpRequestEventTarget XMLHttpRequestUpload".replace(/\w+/g, function (global) {
|
612
|
+
var prototype = window[global] && window[global].prototype;
|
613
|
+
if (prototype && prototype.hasOwnProperty && prototype.hasOwnProperty("addEventListener")) {
|
614
|
+
polyFill(prototype, "addEventListener", hijackEventFunc);
|
615
|
+
// We also need to hack removeEventListener so that you can remove any
|
616
|
+
// event listeners.
|
617
|
+
polyFill(prototype, "removeEventListener", hijackEventFunc);
|
618
|
+
}
|
619
|
+
});
|
620
|
+
}
|
621
|
+
|
622
|
+
return self;
|
623
|
+
});
|