exception_notification_server 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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +51 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +23 -0
- data/Gemfile.lock +162 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/app/assets/images/exception_notification_server/.keep +0 -0
- data/app/assets/javascripts/exception_notification_server/application.js.coffee +8 -0
- data/app/assets/javascripts/exception_notification_server/flot/excanvas.js +1428 -0
- data/app/assets/javascripts/exception_notification_server/flot/jquery.flot.js +3168 -0
- data/app/assets/javascripts/exception_notification_server/flot/jquery.flot.resize.js +59 -0
- data/app/assets/javascripts/exception_notification_server/flot/jquery.flot.time.js +432 -0
- data/app/assets/javascripts/exception_notification_server/jquery.sparkline.js +3054 -0
- data/app/assets/javascripts/exception_notification_server/main.js.coffee +6 -0
- data/app/assets/javascripts/exception_notification_server/pages/notifications.js.coffee +15 -0
- data/app/assets/stylesheets/exception_notification_server/application.css.sass +4 -0
- data/app/assets/stylesheets/exception_notification_server/layout.css.sass +97 -0
- data/app/assets/stylesheets/exception_notification_server/notifications.css.sass +19 -0
- data/app/controllers/exception_notification_server/application_controller.rb +20 -0
- data/app/controllers/exception_notification_server/notifications_controller.rb +97 -0
- data/app/helpers/exception_notification_server/application_helper.rb +46 -0
- data/app/models/exception_notification_server/notification.rb +69 -0
- data/app/views/exception_notification_server/notifications/_notifications.html.haml +37 -0
- data/app/views/exception_notification_server/notifications/index.html.haml +7 -0
- data/app/views/exception_notification_server/notifications/index.js.haml +2 -0
- data/app/views/exception_notification_server/notifications/show.html.haml +76 -0
- data/app/views/layouts/exception_notification_server/application.html.haml +17 -0
- data/config/routes.rb +10 -0
- data/exception_notification_server.gemspec +162 -0
- data/lib/exception_notification_server/engine.rb +10 -0
- data/lib/exception_notification_server/version.rb +3 -0
- data/lib/exception_notification_server.rb +21 -0
- data/lib/generators/exception_notification_server/install_generator.rb +33 -0
- data/lib/generators/exception_notification_server/templates/exception_notification_server.rb +5 -0
- data/lib/generators/exception_notification_server/templates/migration.rb +26 -0
- data/lib/tasks/exception_notification_server_tasks.rake +4 -0
- data/readme.md +5 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/.keep +0 -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/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.keep +0 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/concerns/.keep +0 -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/config/application.rb +22 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/assets.rb +8 -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 +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -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/exception_notification_server_test.rb +7 -0
- data/test/integration/navigation_test.rb +9 -0
- data/test/test_helper.rb +15 -0
- metadata +357 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b1a9b32025e7310064da7e1af6dd5b89a7be29b
|
4
|
+
data.tar.gz: e60b53ecc73a96ae53f430aeac97c76f530d95d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e30a714c2c40b7f0c443176fd5df8b019786793b3b51e2ef9863082697d297ecd1648c68f07bf002cdc3baaf0b4bef600067a4fea27f55647c5475c3981fd5fc
|
7
|
+
data.tar.gz: 52eaf7c726a26ebf863f63875f4c8c211d22a6c0b3cacbd3b9941eaab497a4bee183cee7491737186866fb9762cbcfbbc383847967e79aee9198197d2fceb0b5
|
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
coverage.data
|
4
|
+
|
5
|
+
# rdoc generated
|
6
|
+
rdoc
|
7
|
+
|
8
|
+
# yard generated
|
9
|
+
doc
|
10
|
+
.yardoc
|
11
|
+
|
12
|
+
# bundler
|
13
|
+
.bundle
|
14
|
+
|
15
|
+
# jeweler generated
|
16
|
+
pkg
|
17
|
+
|
18
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
19
|
+
#
|
20
|
+
# * Create a file at ~/.gitignore
|
21
|
+
# * Include files you want ignored
|
22
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
23
|
+
#
|
24
|
+
# After doing this, these files will be ignored in all your git projects,
|
25
|
+
# saving you from having to 'pollute' every project you touch with them
|
26
|
+
#
|
27
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
28
|
+
#
|
29
|
+
# For MacOS:
|
30
|
+
#
|
31
|
+
#.DS_Store
|
32
|
+
|
33
|
+
# For TextMate
|
34
|
+
#*.tmproj
|
35
|
+
#tmtags
|
36
|
+
|
37
|
+
# For emacs:
|
38
|
+
#*~
|
39
|
+
#\#*
|
40
|
+
#.\#*
|
41
|
+
|
42
|
+
# For vim:
|
43
|
+
#*.swp
|
44
|
+
|
45
|
+
# For redcar:
|
46
|
+
#.redcar
|
47
|
+
|
48
|
+
# For rubinius:
|
49
|
+
#*.rbc
|
50
|
+
|
51
|
+
test/dummy/log/*.log
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
exception_notifiaction_server
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.3
|
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
gem 'rails', '~> 4.1'
|
9
|
+
gem 'coderay', '~> 1.1'
|
10
|
+
gem 'jquery-rails'
|
11
|
+
gem 'jquery-ui-rails'
|
12
|
+
gem 'will_paginate'
|
13
|
+
gem 'haml'
|
14
|
+
|
15
|
+
group :development do
|
16
|
+
gem 'sqlite3'
|
17
|
+
gem 'shoulda', '>= 0'
|
18
|
+
gem 'rdoc', '~> 3.12'
|
19
|
+
gem 'bundler', '~> 1.0'
|
20
|
+
gem 'jeweler', '~> 2.0.1'
|
21
|
+
gem 'simplecov', '>= 0'
|
22
|
+
gem 'rubocop'
|
23
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (4.1.13)
|
5
|
+
actionpack (= 4.1.13)
|
6
|
+
actionview (= 4.1.13)
|
7
|
+
mail (~> 2.5, >= 2.5.4)
|
8
|
+
actionpack (4.1.13)
|
9
|
+
actionview (= 4.1.13)
|
10
|
+
activesupport (= 4.1.13)
|
11
|
+
rack (~> 1.5.2)
|
12
|
+
rack-test (~> 0.6.2)
|
13
|
+
actionview (4.1.13)
|
14
|
+
activesupport (= 4.1.13)
|
15
|
+
builder (~> 3.1)
|
16
|
+
erubis (~> 2.7.0)
|
17
|
+
activemodel (4.1.13)
|
18
|
+
activesupport (= 4.1.13)
|
19
|
+
builder (~> 3.1)
|
20
|
+
activerecord (4.1.13)
|
21
|
+
activemodel (= 4.1.13)
|
22
|
+
activesupport (= 4.1.13)
|
23
|
+
arel (~> 5.0.0)
|
24
|
+
activesupport (4.1.13)
|
25
|
+
i18n (~> 0.6, >= 0.6.9)
|
26
|
+
json (~> 1.7, >= 1.7.7)
|
27
|
+
minitest (~> 5.1)
|
28
|
+
thread_safe (~> 0.1)
|
29
|
+
tzinfo (~> 1.1)
|
30
|
+
addressable (2.3.8)
|
31
|
+
arel (5.0.1.20140414130214)
|
32
|
+
ast (2.1.0)
|
33
|
+
astrolabe (1.3.1)
|
34
|
+
parser (~> 2.2)
|
35
|
+
builder (3.2.2)
|
36
|
+
coderay (1.1.0)
|
37
|
+
descendants_tracker (0.0.4)
|
38
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
39
|
+
docile (1.1.5)
|
40
|
+
erubis (2.7.0)
|
41
|
+
faraday (0.9.1)
|
42
|
+
multipart-post (>= 1.2, < 3)
|
43
|
+
git (1.2.9.1)
|
44
|
+
github_api (0.12.4)
|
45
|
+
addressable (~> 2.3)
|
46
|
+
descendants_tracker (~> 0.0.4)
|
47
|
+
faraday (~> 0.8, < 0.10)
|
48
|
+
hashie (>= 3.4)
|
49
|
+
multi_json (>= 1.7.5, < 2.0)
|
50
|
+
nokogiri (~> 1.6.6)
|
51
|
+
oauth2
|
52
|
+
haml (4.0.7)
|
53
|
+
tilt
|
54
|
+
hashie (3.4.2)
|
55
|
+
highline (1.7.7)
|
56
|
+
i18n (0.7.0)
|
57
|
+
jeweler (2.0.1)
|
58
|
+
builder
|
59
|
+
bundler (>= 1.0)
|
60
|
+
git (>= 1.2.5)
|
61
|
+
github_api
|
62
|
+
highline (>= 1.6.15)
|
63
|
+
nokogiri (>= 1.5.10)
|
64
|
+
rake
|
65
|
+
rdoc
|
66
|
+
jquery-rails (3.1.4)
|
67
|
+
railties (>= 3.0, < 5.0)
|
68
|
+
thor (>= 0.14, < 2.0)
|
69
|
+
jquery-ui-rails (5.0.5)
|
70
|
+
railties (>= 3.2.16)
|
71
|
+
json (1.8.3)
|
72
|
+
jwt (1.5.1)
|
73
|
+
mail (2.6.3)
|
74
|
+
mime-types (>= 1.16, < 3)
|
75
|
+
mime-types (2.6.2)
|
76
|
+
mini_portile (0.6.2)
|
77
|
+
minitest (5.8.1)
|
78
|
+
multi_json (1.11.2)
|
79
|
+
multi_xml (0.5.5)
|
80
|
+
multipart-post (2.0.0)
|
81
|
+
nokogiri (1.6.6.2)
|
82
|
+
mini_portile (~> 0.6.0)
|
83
|
+
oauth2 (1.0.0)
|
84
|
+
faraday (>= 0.8, < 0.10)
|
85
|
+
jwt (~> 1.0)
|
86
|
+
multi_json (~> 1.3)
|
87
|
+
multi_xml (~> 0.5)
|
88
|
+
rack (~> 1.2)
|
89
|
+
parser (2.2.2.6)
|
90
|
+
ast (>= 1.1, < 3.0)
|
91
|
+
powerpack (0.1.1)
|
92
|
+
rack (1.5.5)
|
93
|
+
rack-test (0.6.3)
|
94
|
+
rack (>= 1.0)
|
95
|
+
rails (4.1.13)
|
96
|
+
actionmailer (= 4.1.13)
|
97
|
+
actionpack (= 4.1.13)
|
98
|
+
actionview (= 4.1.13)
|
99
|
+
activemodel (= 4.1.13)
|
100
|
+
activerecord (= 4.1.13)
|
101
|
+
activesupport (= 4.1.13)
|
102
|
+
bundler (>= 1.3.0, < 2.0)
|
103
|
+
railties (= 4.1.13)
|
104
|
+
sprockets-rails (~> 2.0)
|
105
|
+
railties (4.1.13)
|
106
|
+
actionpack (= 4.1.13)
|
107
|
+
activesupport (= 4.1.13)
|
108
|
+
rake (>= 0.8.7)
|
109
|
+
thor (>= 0.18.1, < 2.0)
|
110
|
+
rainbow (2.0.0)
|
111
|
+
rake (10.4.2)
|
112
|
+
rdoc (3.12.2)
|
113
|
+
json (~> 1.4)
|
114
|
+
rubocop (0.34.2)
|
115
|
+
astrolabe (~> 1.3)
|
116
|
+
parser (>= 2.2.2.5, < 3.0)
|
117
|
+
powerpack (~> 0.1)
|
118
|
+
rainbow (>= 1.99.1, < 3.0)
|
119
|
+
ruby-progressbar (~> 1.4)
|
120
|
+
ruby-progressbar (1.7.5)
|
121
|
+
shoulda (3.5.0)
|
122
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
123
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
124
|
+
shoulda-context (1.2.1)
|
125
|
+
shoulda-matchers (2.8.0)
|
126
|
+
activesupport (>= 3.0.0)
|
127
|
+
simplecov (0.10.0)
|
128
|
+
docile (~> 1.1.0)
|
129
|
+
json (~> 1.8)
|
130
|
+
simplecov-html (~> 0.10.0)
|
131
|
+
simplecov-html (0.10.0)
|
132
|
+
sprockets (3.3.5)
|
133
|
+
rack (> 1, < 3)
|
134
|
+
sprockets-rails (2.3.3)
|
135
|
+
actionpack (>= 3.0)
|
136
|
+
activesupport (>= 3.0)
|
137
|
+
sprockets (>= 2.8, < 4.0)
|
138
|
+
sqlite3 (1.3.10)
|
139
|
+
thor (0.19.1)
|
140
|
+
thread_safe (0.3.5)
|
141
|
+
tilt (2.0.1)
|
142
|
+
tzinfo (1.2.2)
|
143
|
+
thread_safe (~> 0.1)
|
144
|
+
will_paginate (3.0.7)
|
145
|
+
|
146
|
+
PLATFORMS
|
147
|
+
ruby
|
148
|
+
|
149
|
+
DEPENDENCIES
|
150
|
+
bundler (~> 1.0)
|
151
|
+
coderay (~> 1.1)
|
152
|
+
haml
|
153
|
+
jeweler (~> 2.0.1)
|
154
|
+
jquery-rails
|
155
|
+
jquery-ui-rails
|
156
|
+
rails (~> 4.1)
|
157
|
+
rdoc (~> 3.12)
|
158
|
+
rubocop
|
159
|
+
shoulda
|
160
|
+
simplecov
|
161
|
+
sqlite3
|
162
|
+
will_paginate
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Anatoliy Varanitsa
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= exception_notification_server
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to exception_notification_server
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
|
+
* Fork the project.
|
10
|
+
* Start a feature/bugfix branch.
|
11
|
+
* Commit and push until you are happy with your contribution.
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2015 Anatoliy Varanitsa. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
15
|
+
load 'rails/tasks/engine.rake'
|
16
|
+
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gem|
|
19
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
20
|
+
gem.name = 'exception_notification_server'
|
21
|
+
gem.homepage = 'http://github.com/prizrack13/exception_notification_server'
|
22
|
+
gem.license = 'MIT'
|
23
|
+
gem.summary = %(Exception Notifiaction Server)
|
24
|
+
gem.description = %(Gem that receive errors from exception_notification gem and show it grouped on pages)
|
25
|
+
gem.email = 'Prizrack13@mail.ru'
|
26
|
+
gem.authors = ['Anatoliy Varanitsa']
|
27
|
+
gem.platform = Gem::Platform::RUBY
|
28
|
+
gem.required_ruby_version = '>= 1.9.2'
|
29
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).delete_if { |f| f == 'bin/rails' }
|
30
|
+
gem.executables = gem.files.grep(%r{^bin\/}) { |f| File.basename(f) }.delete_if { |f| f == 'rails' }
|
31
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)\/})
|
32
|
+
# dependencies defined in Gemfile
|
33
|
+
end
|
34
|
+
Jeweler::RubygemsDotOrgTasks.new
|
35
|
+
|
36
|
+
require 'rake/testtask'
|
37
|
+
Rake::TestTask.new(:test) do |test|
|
38
|
+
test.libs << 'lib' << 'test'
|
39
|
+
test.pattern = 'test/**/*_test.rb'
|
40
|
+
test.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Code coverage detail'
|
44
|
+
task :simplecov do
|
45
|
+
ENV['COVERAGE'] = 'true'
|
46
|
+
Rake::Task['test'].execute
|
47
|
+
end
|
48
|
+
|
49
|
+
task default: :test
|
50
|
+
|
51
|
+
require 'rdoc/task'
|
52
|
+
Rake::RDocTask.new do |rdoc|
|
53
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ''
|
54
|
+
|
55
|
+
rdoc.rdoc_dir = 'rdoc'
|
56
|
+
rdoc.title = "exception_notification_server #{version}"
|
57
|
+
rdoc.rdoc_files.include('README*')
|
58
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
File without changes
|
@@ -0,0 +1,8 @@
|
|
1
|
+
#= require jquery
|
2
|
+
#= require jquery_ujs
|
3
|
+
#= require exception_notification_server/jquery.sparkline
|
4
|
+
#= require exception_notification_server/flot/jquery.flot
|
5
|
+
#= require exception_notification_server/flot/jquery.flot.time
|
6
|
+
#= require exception_notification_server/flot/jquery.flot.resize
|
7
|
+
#= require exception_notification_server/pages/notifications
|
8
|
+
#= require exception_notification_server/main
|
@@ -0,0 +1,1428 @@
|
|
1
|
+
// Copyright 2006 Google Inc.
|
2
|
+
//
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
// you may not use this file except in compliance with the License.
|
5
|
+
// You may obtain a copy of the License at
|
6
|
+
//
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
//
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
// See the License for the specific language governing permissions and
|
13
|
+
// limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
// Known Issues:
|
17
|
+
//
|
18
|
+
// * Patterns only support repeat.
|
19
|
+
// * Radial gradient are not implemented. The VML version of these look very
|
20
|
+
// different from the canvas one.
|
21
|
+
// * Clipping paths are not implemented.
|
22
|
+
// * Coordsize. The width and height attribute have higher priority than the
|
23
|
+
// width and height style values which isn't correct.
|
24
|
+
// * Painting mode isn't implemented.
|
25
|
+
// * Canvas width/height should is using content-box by default. IE in
|
26
|
+
// Quirks mode will draw the canvas using border-box. Either change your
|
27
|
+
// doctype to HTML5
|
28
|
+
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
|
29
|
+
// or use Box Sizing Behavior from WebFX
|
30
|
+
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
|
31
|
+
// * Non uniform scaling does not correctly scale strokes.
|
32
|
+
// * Filling very large shapes (above 5000 points) is buggy.
|
33
|
+
// * Optimize. There is always room for speed improvements.
|
34
|
+
|
35
|
+
// Only add this code if we do not already have a canvas implementation
|
36
|
+
if (!document.createElement('canvas').getContext) {
|
37
|
+
|
38
|
+
(function() {
|
39
|
+
|
40
|
+
// alias some functions to make (compiled) code shorter
|
41
|
+
var m = Math;
|
42
|
+
var mr = m.round;
|
43
|
+
var ms = m.sin;
|
44
|
+
var mc = m.cos;
|
45
|
+
var abs = m.abs;
|
46
|
+
var sqrt = m.sqrt;
|
47
|
+
|
48
|
+
// this is used for sub pixel precision
|
49
|
+
var Z = 10;
|
50
|
+
var Z2 = Z / 2;
|
51
|
+
|
52
|
+
var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1];
|
53
|
+
|
54
|
+
/**
|
55
|
+
* This funtion is assigned to the <canvas> elements as element.getContext().
|
56
|
+
* @this {HTMLElement}
|
57
|
+
* @return {CanvasRenderingContext2D_}
|
58
|
+
*/
|
59
|
+
function getContext() {
|
60
|
+
return this.context_ ||
|
61
|
+
(this.context_ = new CanvasRenderingContext2D_(this));
|
62
|
+
}
|
63
|
+
|
64
|
+
var slice = Array.prototype.slice;
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Binds a function to an object. The returned function will always use the
|
68
|
+
* passed in {@code obj} as {@code this}.
|
69
|
+
*
|
70
|
+
* Example:
|
71
|
+
*
|
72
|
+
* g = bind(f, obj, a, b)
|
73
|
+
* g(c, d) // will do f.call(obj, a, b, c, d)
|
74
|
+
*
|
75
|
+
* @param {Function} f The function to bind the object to
|
76
|
+
* @param {Object} obj The object that should act as this when the function
|
77
|
+
* is called
|
78
|
+
* @param {*} var_args Rest arguments that will be used as the initial
|
79
|
+
* arguments when the function is called
|
80
|
+
* @return {Function} A new function that has bound this
|
81
|
+
*/
|
82
|
+
function bind(f, obj, var_args) {
|
83
|
+
var a = slice.call(arguments, 2);
|
84
|
+
return function() {
|
85
|
+
return f.apply(obj, a.concat(slice.call(arguments)));
|
86
|
+
};
|
87
|
+
}
|
88
|
+
|
89
|
+
function encodeHtmlAttribute(s) {
|
90
|
+
return String(s).replace(/&/g, '&').replace(/"/g, '"');
|
91
|
+
}
|
92
|
+
|
93
|
+
function addNamespace(doc, prefix, urn) {
|
94
|
+
if (!doc.namespaces[prefix]) {
|
95
|
+
doc.namespaces.add(prefix, urn, '#default#VML');
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
function addNamespacesAndStylesheet(doc) {
|
100
|
+
addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml');
|
101
|
+
addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office');
|
102
|
+
|
103
|
+
// Setup default CSS. Only add one style sheet per document
|
104
|
+
if (!doc.styleSheets['ex_canvas_']) {
|
105
|
+
var ss = doc.createStyleSheet();
|
106
|
+
ss.owningElement.id = 'ex_canvas_';
|
107
|
+
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
|
108
|
+
// default size is 300x150 in Gecko and Opera
|
109
|
+
'text-align:left;width:300px;height:150px}';
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
// Add namespaces and stylesheet at startup.
|
114
|
+
addNamespacesAndStylesheet(document);
|
115
|
+
|
116
|
+
var G_vmlCanvasManager_ = {
|
117
|
+
init: function(opt_doc) {
|
118
|
+
var doc = opt_doc || document;
|
119
|
+
// Create a dummy element so that IE will allow canvas elements to be
|
120
|
+
// recognized.
|
121
|
+
doc.createElement('canvas');
|
122
|
+
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
|
123
|
+
},
|
124
|
+
|
125
|
+
init_: function(doc) {
|
126
|
+
// find all canvas elements
|
127
|
+
var els = doc.getElementsByTagName('canvas');
|
128
|
+
for (var i = 0; i < els.length; i++) {
|
129
|
+
this.initElement(els[i]);
|
130
|
+
}
|
131
|
+
},
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Public initializes a canvas element so that it can be used as canvas
|
135
|
+
* element from now on. This is called automatically before the page is
|
136
|
+
* loaded but if you are creating elements using createElement you need to
|
137
|
+
* make sure this is called on the element.
|
138
|
+
* @param {HTMLElement} el The canvas element to initialize.
|
139
|
+
* @return {HTMLElement} the element that was created.
|
140
|
+
*/
|
141
|
+
initElement: function(el) {
|
142
|
+
if (!el.getContext) {
|
143
|
+
el.getContext = getContext;
|
144
|
+
|
145
|
+
// Add namespaces and stylesheet to document of the element.
|
146
|
+
addNamespacesAndStylesheet(el.ownerDocument);
|
147
|
+
|
148
|
+
// Remove fallback content. There is no way to hide text nodes so we
|
149
|
+
// just remove all childNodes. We could hide all elements and remove
|
150
|
+
// text nodes but who really cares about the fallback content.
|
151
|
+
el.innerHTML = '';
|
152
|
+
|
153
|
+
// do not use inline function because that will leak memory
|
154
|
+
el.attachEvent('onpropertychange', onPropertyChange);
|
155
|
+
el.attachEvent('onresize', onResize);
|
156
|
+
|
157
|
+
var attrs = el.attributes;
|
158
|
+
if (attrs.width && attrs.width.specified) {
|
159
|
+
// TODO: use runtimeStyle and coordsize
|
160
|
+
// el.getContext().setWidth_(attrs.width.nodeValue);
|
161
|
+
el.style.width = attrs.width.nodeValue + 'px';
|
162
|
+
} else {
|
163
|
+
el.width = el.clientWidth;
|
164
|
+
}
|
165
|
+
if (attrs.height && attrs.height.specified) {
|
166
|
+
// TODO: use runtimeStyle and coordsize
|
167
|
+
// el.getContext().setHeight_(attrs.height.nodeValue);
|
168
|
+
el.style.height = attrs.height.nodeValue + 'px';
|
169
|
+
} else {
|
170
|
+
el.height = el.clientHeight;
|
171
|
+
}
|
172
|
+
//el.getContext().setCoordsize_()
|
173
|
+
}
|
174
|
+
return el;
|
175
|
+
}
|
176
|
+
};
|
177
|
+
|
178
|
+
function onPropertyChange(e) {
|
179
|
+
var el = e.srcElement;
|
180
|
+
|
181
|
+
switch (e.propertyName) {
|
182
|
+
case 'width':
|
183
|
+
el.getContext().clearRect();
|
184
|
+
el.style.width = el.attributes.width.nodeValue + 'px';
|
185
|
+
// In IE8 this does not trigger onresize.
|
186
|
+
el.firstChild.style.width = el.clientWidth + 'px';
|
187
|
+
break;
|
188
|
+
case 'height':
|
189
|
+
el.getContext().clearRect();
|
190
|
+
el.style.height = el.attributes.height.nodeValue + 'px';
|
191
|
+
el.firstChild.style.height = el.clientHeight + 'px';
|
192
|
+
break;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
function onResize(e) {
|
197
|
+
var el = e.srcElement;
|
198
|
+
if (el.firstChild) {
|
199
|
+
el.firstChild.style.width = el.clientWidth + 'px';
|
200
|
+
el.firstChild.style.height = el.clientHeight + 'px';
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
G_vmlCanvasManager_.init();
|
205
|
+
|
206
|
+
// precompute "00" to "FF"
|
207
|
+
var decToHex = [];
|
208
|
+
for (var i = 0; i < 16; i++) {
|
209
|
+
for (var j = 0; j < 16; j++) {
|
210
|
+
decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
function createMatrixIdentity() {
|
215
|
+
return [
|
216
|
+
[1, 0, 0],
|
217
|
+
[0, 1, 0],
|
218
|
+
[0, 0, 1]
|
219
|
+
];
|
220
|
+
}
|
221
|
+
|
222
|
+
function matrixMultiply(m1, m2) {
|
223
|
+
var result = createMatrixIdentity();
|
224
|
+
|
225
|
+
for (var x = 0; x < 3; x++) {
|
226
|
+
for (var y = 0; y < 3; y++) {
|
227
|
+
var sum = 0;
|
228
|
+
|
229
|
+
for (var z = 0; z < 3; z++) {
|
230
|
+
sum += m1[x][z] * m2[z][y];
|
231
|
+
}
|
232
|
+
|
233
|
+
result[x][y] = sum;
|
234
|
+
}
|
235
|
+
}
|
236
|
+
return result;
|
237
|
+
}
|
238
|
+
|
239
|
+
function copyState(o1, o2) {
|
240
|
+
o2.fillStyle = o1.fillStyle;
|
241
|
+
o2.lineCap = o1.lineCap;
|
242
|
+
o2.lineJoin = o1.lineJoin;
|
243
|
+
o2.lineWidth = o1.lineWidth;
|
244
|
+
o2.miterLimit = o1.miterLimit;
|
245
|
+
o2.shadowBlur = o1.shadowBlur;
|
246
|
+
o2.shadowColor = o1.shadowColor;
|
247
|
+
o2.shadowOffsetX = o1.shadowOffsetX;
|
248
|
+
o2.shadowOffsetY = o1.shadowOffsetY;
|
249
|
+
o2.strokeStyle = o1.strokeStyle;
|
250
|
+
o2.globalAlpha = o1.globalAlpha;
|
251
|
+
o2.font = o1.font;
|
252
|
+
o2.textAlign = o1.textAlign;
|
253
|
+
o2.textBaseline = o1.textBaseline;
|
254
|
+
o2.arcScaleX_ = o1.arcScaleX_;
|
255
|
+
o2.arcScaleY_ = o1.arcScaleY_;
|
256
|
+
o2.lineScale_ = o1.lineScale_;
|
257
|
+
}
|
258
|
+
|
259
|
+
var colorData = {
|
260
|
+
aliceblue: '#F0F8FF',
|
261
|
+
antiquewhite: '#FAEBD7',
|
262
|
+
aquamarine: '#7FFFD4',
|
263
|
+
azure: '#F0FFFF',
|
264
|
+
beige: '#F5F5DC',
|
265
|
+
bisque: '#FFE4C4',
|
266
|
+
black: '#000000',
|
267
|
+
blanchedalmond: '#FFEBCD',
|
268
|
+
blueviolet: '#8A2BE2',
|
269
|
+
brown: '#A52A2A',
|
270
|
+
burlywood: '#DEB887',
|
271
|
+
cadetblue: '#5F9EA0',
|
272
|
+
chartreuse: '#7FFF00',
|
273
|
+
chocolate: '#D2691E',
|
274
|
+
coral: '#FF7F50',
|
275
|
+
cornflowerblue: '#6495ED',
|
276
|
+
cornsilk: '#FFF8DC',
|
277
|
+
crimson: '#DC143C',
|
278
|
+
cyan: '#00FFFF',
|
279
|
+
darkblue: '#00008B',
|
280
|
+
darkcyan: '#008B8B',
|
281
|
+
darkgoldenrod: '#B8860B',
|
282
|
+
darkgray: '#A9A9A9',
|
283
|
+
darkgreen: '#006400',
|
284
|
+
darkgrey: '#A9A9A9',
|
285
|
+
darkkhaki: '#BDB76B',
|
286
|
+
darkmagenta: '#8B008B',
|
287
|
+
darkolivegreen: '#556B2F',
|
288
|
+
darkorange: '#FF8C00',
|
289
|
+
darkorchid: '#9932CC',
|
290
|
+
darkred: '#8B0000',
|
291
|
+
darksalmon: '#E9967A',
|
292
|
+
darkseagreen: '#8FBC8F',
|
293
|
+
darkslateblue: '#483D8B',
|
294
|
+
darkslategray: '#2F4F4F',
|
295
|
+
darkslategrey: '#2F4F4F',
|
296
|
+
darkturquoise: '#00CED1',
|
297
|
+
darkviolet: '#9400D3',
|
298
|
+
deeppink: '#FF1493',
|
299
|
+
deepskyblue: '#00BFFF',
|
300
|
+
dimgray: '#696969',
|
301
|
+
dimgrey: '#696969',
|
302
|
+
dodgerblue: '#1E90FF',
|
303
|
+
firebrick: '#B22222',
|
304
|
+
floralwhite: '#FFFAF0',
|
305
|
+
forestgreen: '#228B22',
|
306
|
+
gainsboro: '#DCDCDC',
|
307
|
+
ghostwhite: '#F8F8FF',
|
308
|
+
gold: '#FFD700',
|
309
|
+
goldenrod: '#DAA520',
|
310
|
+
grey: '#808080',
|
311
|
+
greenyellow: '#ADFF2F',
|
312
|
+
honeydew: '#F0FFF0',
|
313
|
+
hotpink: '#FF69B4',
|
314
|
+
indianred: '#CD5C5C',
|
315
|
+
indigo: '#4B0082',
|
316
|
+
ivory: '#FFFFF0',
|
317
|
+
khaki: '#F0E68C',
|
318
|
+
lavender: '#E6E6FA',
|
319
|
+
lavenderblush: '#FFF0F5',
|
320
|
+
lawngreen: '#7CFC00',
|
321
|
+
lemonchiffon: '#FFFACD',
|
322
|
+
lightblue: '#ADD8E6',
|
323
|
+
lightcoral: '#F08080',
|
324
|
+
lightcyan: '#E0FFFF',
|
325
|
+
lightgoldenrodyellow: '#FAFAD2',
|
326
|
+
lightgreen: '#90EE90',
|
327
|
+
lightgrey: '#D3D3D3',
|
328
|
+
lightpink: '#FFB6C1',
|
329
|
+
lightsalmon: '#FFA07A',
|
330
|
+
lightseagreen: '#20B2AA',
|
331
|
+
lightskyblue: '#87CEFA',
|
332
|
+
lightslategray: '#778899',
|
333
|
+
lightslategrey: '#778899',
|
334
|
+
lightsteelblue: '#B0C4DE',
|
335
|
+
lightyellow: '#FFFFE0',
|
336
|
+
limegreen: '#32CD32',
|
337
|
+
linen: '#FAF0E6',
|
338
|
+
magenta: '#FF00FF',
|
339
|
+
mediumaquamarine: '#66CDAA',
|
340
|
+
mediumblue: '#0000CD',
|
341
|
+
mediumorchid: '#BA55D3',
|
342
|
+
mediumpurple: '#9370DB',
|
343
|
+
mediumseagreen: '#3CB371',
|
344
|
+
mediumslateblue: '#7B68EE',
|
345
|
+
mediumspringgreen: '#00FA9A',
|
346
|
+
mediumturquoise: '#48D1CC',
|
347
|
+
mediumvioletred: '#C71585',
|
348
|
+
midnightblue: '#191970',
|
349
|
+
mintcream: '#F5FFFA',
|
350
|
+
mistyrose: '#FFE4E1',
|
351
|
+
moccasin: '#FFE4B5',
|
352
|
+
navajowhite: '#FFDEAD',
|
353
|
+
oldlace: '#FDF5E6',
|
354
|
+
olivedrab: '#6B8E23',
|
355
|
+
orange: '#FFA500',
|
356
|
+
orangered: '#FF4500',
|
357
|
+
orchid: '#DA70D6',
|
358
|
+
palegoldenrod: '#EEE8AA',
|
359
|
+
palegreen: '#98FB98',
|
360
|
+
paleturquoise: '#AFEEEE',
|
361
|
+
palevioletred: '#DB7093',
|
362
|
+
papayawhip: '#FFEFD5',
|
363
|
+
peachpuff: '#FFDAB9',
|
364
|
+
peru: '#CD853F',
|
365
|
+
pink: '#FFC0CB',
|
366
|
+
plum: '#DDA0DD',
|
367
|
+
powderblue: '#B0E0E6',
|
368
|
+
rosybrown: '#BC8F8F',
|
369
|
+
royalblue: '#4169E1',
|
370
|
+
saddlebrown: '#8B4513',
|
371
|
+
salmon: '#FA8072',
|
372
|
+
sandybrown: '#F4A460',
|
373
|
+
seagreen: '#2E8B57',
|
374
|
+
seashell: '#FFF5EE',
|
375
|
+
sienna: '#A0522D',
|
376
|
+
skyblue: '#87CEEB',
|
377
|
+
slateblue: '#6A5ACD',
|
378
|
+
slategray: '#708090',
|
379
|
+
slategrey: '#708090',
|
380
|
+
snow: '#FFFAFA',
|
381
|
+
springgreen: '#00FF7F',
|
382
|
+
steelblue: '#4682B4',
|
383
|
+
tan: '#D2B48C',
|
384
|
+
thistle: '#D8BFD8',
|
385
|
+
tomato: '#FF6347',
|
386
|
+
turquoise: '#40E0D0',
|
387
|
+
violet: '#EE82EE',
|
388
|
+
wheat: '#F5DEB3',
|
389
|
+
whitesmoke: '#F5F5F5',
|
390
|
+
yellowgreen: '#9ACD32'
|
391
|
+
};
|
392
|
+
|
393
|
+
|
394
|
+
function getRgbHslContent(styleString) {
|
395
|
+
var start = styleString.indexOf('(', 3);
|
396
|
+
var end = styleString.indexOf(')', start + 1);
|
397
|
+
var parts = styleString.substring(start + 1, end).split(',');
|
398
|
+
// add alpha if needed
|
399
|
+
if (parts.length != 4 || styleString.charAt(3) != 'a') {
|
400
|
+
parts[3] = 1;
|
401
|
+
}
|
402
|
+
return parts;
|
403
|
+
}
|
404
|
+
|
405
|
+
function percent(s) {
|
406
|
+
return parseFloat(s) / 100;
|
407
|
+
}
|
408
|
+
|
409
|
+
function clamp(v, min, max) {
|
410
|
+
return Math.min(max, Math.max(min, v));
|
411
|
+
}
|
412
|
+
|
413
|
+
function hslToRgb(parts){
|
414
|
+
var r, g, b, h, s, l;
|
415
|
+
h = parseFloat(parts[0]) / 360 % 360;
|
416
|
+
if (h < 0)
|
417
|
+
h++;
|
418
|
+
s = clamp(percent(parts[1]), 0, 1);
|
419
|
+
l = clamp(percent(parts[2]), 0, 1);
|
420
|
+
if (s == 0) {
|
421
|
+
r = g = b = l; // achromatic
|
422
|
+
} else {
|
423
|
+
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
424
|
+
var p = 2 * l - q;
|
425
|
+
r = hueToRgb(p, q, h + 1 / 3);
|
426
|
+
g = hueToRgb(p, q, h);
|
427
|
+
b = hueToRgb(p, q, h - 1 / 3);
|
428
|
+
}
|
429
|
+
|
430
|
+
return '#' + decToHex[Math.floor(r * 255)] +
|
431
|
+
decToHex[Math.floor(g * 255)] +
|
432
|
+
decToHex[Math.floor(b * 255)];
|
433
|
+
}
|
434
|
+
|
435
|
+
function hueToRgb(m1, m2, h) {
|
436
|
+
if (h < 0)
|
437
|
+
h++;
|
438
|
+
if (h > 1)
|
439
|
+
h--;
|
440
|
+
|
441
|
+
if (6 * h < 1)
|
442
|
+
return m1 + (m2 - m1) * 6 * h;
|
443
|
+
else if (2 * h < 1)
|
444
|
+
return m2;
|
445
|
+
else if (3 * h < 2)
|
446
|
+
return m1 + (m2 - m1) * (2 / 3 - h) * 6;
|
447
|
+
else
|
448
|
+
return m1;
|
449
|
+
}
|
450
|
+
|
451
|
+
var processStyleCache = {};
|
452
|
+
|
453
|
+
function processStyle(styleString) {
|
454
|
+
if (styleString in processStyleCache) {
|
455
|
+
return processStyleCache[styleString];
|
456
|
+
}
|
457
|
+
|
458
|
+
var str, alpha = 1;
|
459
|
+
|
460
|
+
styleString = String(styleString);
|
461
|
+
if (styleString.charAt(0) == '#') {
|
462
|
+
str = styleString;
|
463
|
+
} else if (/^rgb/.test(styleString)) {
|
464
|
+
var parts = getRgbHslContent(styleString);
|
465
|
+
var str = '#', n;
|
466
|
+
for (var i = 0; i < 3; i++) {
|
467
|
+
if (parts[i].indexOf('%') != -1) {
|
468
|
+
n = Math.floor(percent(parts[i]) * 255);
|
469
|
+
} else {
|
470
|
+
n = +parts[i];
|
471
|
+
}
|
472
|
+
str += decToHex[clamp(n, 0, 255)];
|
473
|
+
}
|
474
|
+
alpha = +parts[3];
|
475
|
+
} else if (/^hsl/.test(styleString)) {
|
476
|
+
var parts = getRgbHslContent(styleString);
|
477
|
+
str = hslToRgb(parts);
|
478
|
+
alpha = parts[3];
|
479
|
+
} else {
|
480
|
+
str = colorData[styleString] || styleString;
|
481
|
+
}
|
482
|
+
return processStyleCache[styleString] = {color: str, alpha: alpha};
|
483
|
+
}
|
484
|
+
|
485
|
+
var DEFAULT_STYLE = {
|
486
|
+
style: 'normal',
|
487
|
+
variant: 'normal',
|
488
|
+
weight: 'normal',
|
489
|
+
size: 10,
|
490
|
+
family: 'sans-serif'
|
491
|
+
};
|
492
|
+
|
493
|
+
// Internal text style cache
|
494
|
+
var fontStyleCache = {};
|
495
|
+
|
496
|
+
function processFontStyle(styleString) {
|
497
|
+
if (fontStyleCache[styleString]) {
|
498
|
+
return fontStyleCache[styleString];
|
499
|
+
}
|
500
|
+
|
501
|
+
var el = document.createElement('div');
|
502
|
+
var style = el.style;
|
503
|
+
try {
|
504
|
+
style.font = styleString;
|
505
|
+
} catch (ex) {
|
506
|
+
// Ignore failures to set to invalid font.
|
507
|
+
}
|
508
|
+
|
509
|
+
return fontStyleCache[styleString] = {
|
510
|
+
style: style.fontStyle || DEFAULT_STYLE.style,
|
511
|
+
variant: style.fontVariant || DEFAULT_STYLE.variant,
|
512
|
+
weight: style.fontWeight || DEFAULT_STYLE.weight,
|
513
|
+
size: style.fontSize || DEFAULT_STYLE.size,
|
514
|
+
family: style.fontFamily || DEFAULT_STYLE.family
|
515
|
+
};
|
516
|
+
}
|
517
|
+
|
518
|
+
function getComputedStyle(style, element) {
|
519
|
+
var computedStyle = {};
|
520
|
+
|
521
|
+
for (var p in style) {
|
522
|
+
computedStyle[p] = style[p];
|
523
|
+
}
|
524
|
+
|
525
|
+
// Compute the size
|
526
|
+
var canvasFontSize = parseFloat(element.currentStyle.fontSize),
|
527
|
+
fontSize = parseFloat(style.size);
|
528
|
+
|
529
|
+
if (typeof style.size == 'number') {
|
530
|
+
computedStyle.size = style.size;
|
531
|
+
} else if (style.size.indexOf('px') != -1) {
|
532
|
+
computedStyle.size = fontSize;
|
533
|
+
} else if (style.size.indexOf('em') != -1) {
|
534
|
+
computedStyle.size = canvasFontSize * fontSize;
|
535
|
+
} else if(style.size.indexOf('%') != -1) {
|
536
|
+
computedStyle.size = (canvasFontSize / 100) * fontSize;
|
537
|
+
} else if (style.size.indexOf('pt') != -1) {
|
538
|
+
computedStyle.size = fontSize / .75;
|
539
|
+
} else {
|
540
|
+
computedStyle.size = canvasFontSize;
|
541
|
+
}
|
542
|
+
|
543
|
+
// Different scaling between normal text and VML text. This was found using
|
544
|
+
// trial and error to get the same size as non VML text.
|
545
|
+
computedStyle.size *= 0.981;
|
546
|
+
|
547
|
+
return computedStyle;
|
548
|
+
}
|
549
|
+
|
550
|
+
function buildStyle(style) {
|
551
|
+
return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
|
552
|
+
style.size + 'px ' + style.family;
|
553
|
+
}
|
554
|
+
|
555
|
+
var lineCapMap = {
|
556
|
+
'butt': 'flat',
|
557
|
+
'round': 'round'
|
558
|
+
};
|
559
|
+
|
560
|
+
function processLineCap(lineCap) {
|
561
|
+
return lineCapMap[lineCap] || 'square';
|
562
|
+
}
|
563
|
+
|
564
|
+
/**
|
565
|
+
* This class implements CanvasRenderingContext2D interface as described by
|
566
|
+
* the WHATWG.
|
567
|
+
* @param {HTMLElement} canvasElement The element that the 2D context should
|
568
|
+
* be associated with
|
569
|
+
*/
|
570
|
+
function CanvasRenderingContext2D_(canvasElement) {
|
571
|
+
this.m_ = createMatrixIdentity();
|
572
|
+
|
573
|
+
this.mStack_ = [];
|
574
|
+
this.aStack_ = [];
|
575
|
+
this.currentPath_ = [];
|
576
|
+
|
577
|
+
// Canvas context properties
|
578
|
+
this.strokeStyle = '#000';
|
579
|
+
this.fillStyle = '#000';
|
580
|
+
|
581
|
+
this.lineWidth = 1;
|
582
|
+
this.lineJoin = 'miter';
|
583
|
+
this.lineCap = 'butt';
|
584
|
+
this.miterLimit = Z * 1;
|
585
|
+
this.globalAlpha = 1;
|
586
|
+
this.font = '10px sans-serif';
|
587
|
+
this.textAlign = 'left';
|
588
|
+
this.textBaseline = 'alphabetic';
|
589
|
+
this.canvas = canvasElement;
|
590
|
+
|
591
|
+
var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' +
|
592
|
+
canvasElement.clientHeight + 'px;overflow:hidden;position:absolute';
|
593
|
+
var el = canvasElement.ownerDocument.createElement('div');
|
594
|
+
el.style.cssText = cssText;
|
595
|
+
canvasElement.appendChild(el);
|
596
|
+
|
597
|
+
var overlayEl = el.cloneNode(false);
|
598
|
+
// Use a non transparent background.
|
599
|
+
overlayEl.style.backgroundColor = 'red';
|
600
|
+
overlayEl.style.filter = 'alpha(opacity=0)';
|
601
|
+
canvasElement.appendChild(overlayEl);
|
602
|
+
|
603
|
+
this.element_ = el;
|
604
|
+
this.arcScaleX_ = 1;
|
605
|
+
this.arcScaleY_ = 1;
|
606
|
+
this.lineScale_ = 1;
|
607
|
+
}
|
608
|
+
|
609
|
+
var contextPrototype = CanvasRenderingContext2D_.prototype;
|
610
|
+
contextPrototype.clearRect = function() {
|
611
|
+
if (this.textMeasureEl_) {
|
612
|
+
this.textMeasureEl_.removeNode(true);
|
613
|
+
this.textMeasureEl_ = null;
|
614
|
+
}
|
615
|
+
this.element_.innerHTML = '';
|
616
|
+
};
|
617
|
+
|
618
|
+
contextPrototype.beginPath = function() {
|
619
|
+
// TODO: Branch current matrix so that save/restore has no effect
|
620
|
+
// as per safari docs.
|
621
|
+
this.currentPath_ = [];
|
622
|
+
};
|
623
|
+
|
624
|
+
contextPrototype.moveTo = function(aX, aY) {
|
625
|
+
var p = getCoords(this, aX, aY);
|
626
|
+
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
|
627
|
+
this.currentX_ = p.x;
|
628
|
+
this.currentY_ = p.y;
|
629
|
+
};
|
630
|
+
|
631
|
+
contextPrototype.lineTo = function(aX, aY) {
|
632
|
+
var p = getCoords(this, aX, aY);
|
633
|
+
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
|
634
|
+
|
635
|
+
this.currentX_ = p.x;
|
636
|
+
this.currentY_ = p.y;
|
637
|
+
};
|
638
|
+
|
639
|
+
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
|
640
|
+
aCP2x, aCP2y,
|
641
|
+
aX, aY) {
|
642
|
+
var p = getCoords(this, aX, aY);
|
643
|
+
var cp1 = getCoords(this, aCP1x, aCP1y);
|
644
|
+
var cp2 = getCoords(this, aCP2x, aCP2y);
|
645
|
+
bezierCurveTo(this, cp1, cp2, p);
|
646
|
+
};
|
647
|
+
|
648
|
+
// Helper function that takes the already fixed cordinates.
|
649
|
+
function bezierCurveTo(self, cp1, cp2, p) {
|
650
|
+
self.currentPath_.push({
|
651
|
+
type: 'bezierCurveTo',
|
652
|
+
cp1x: cp1.x,
|
653
|
+
cp1y: cp1.y,
|
654
|
+
cp2x: cp2.x,
|
655
|
+
cp2y: cp2.y,
|
656
|
+
x: p.x,
|
657
|
+
y: p.y
|
658
|
+
});
|
659
|
+
self.currentX_ = p.x;
|
660
|
+
self.currentY_ = p.y;
|
661
|
+
}
|
662
|
+
|
663
|
+
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
|
664
|
+
// the following is lifted almost directly from
|
665
|
+
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
|
666
|
+
|
667
|
+
var cp = getCoords(this, aCPx, aCPy);
|
668
|
+
var p = getCoords(this, aX, aY);
|
669
|
+
|
670
|
+
var cp1 = {
|
671
|
+
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
|
672
|
+
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
|
673
|
+
};
|
674
|
+
var cp2 = {
|
675
|
+
x: cp1.x + (p.x - this.currentX_) / 3.0,
|
676
|
+
y: cp1.y + (p.y - this.currentY_) / 3.0
|
677
|
+
};
|
678
|
+
|
679
|
+
bezierCurveTo(this, cp1, cp2, p);
|
680
|
+
};
|
681
|
+
|
682
|
+
contextPrototype.arc = function(aX, aY, aRadius,
|
683
|
+
aStartAngle, aEndAngle, aClockwise) {
|
684
|
+
aRadius *= Z;
|
685
|
+
var arcType = aClockwise ? 'at' : 'wa';
|
686
|
+
|
687
|
+
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
|
688
|
+
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
|
689
|
+
|
690
|
+
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
|
691
|
+
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
|
692
|
+
|
693
|
+
// IE won't render arches drawn counter clockwise if xStart == xEnd.
|
694
|
+
if (xStart == xEnd && !aClockwise) {
|
695
|
+
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
|
696
|
+
// that can be represented in binary
|
697
|
+
}
|
698
|
+
|
699
|
+
var p = getCoords(this, aX, aY);
|
700
|
+
var pStart = getCoords(this, xStart, yStart);
|
701
|
+
var pEnd = getCoords(this, xEnd, yEnd);
|
702
|
+
|
703
|
+
this.currentPath_.push({type: arcType,
|
704
|
+
x: p.x,
|
705
|
+
y: p.y,
|
706
|
+
radius: aRadius,
|
707
|
+
xStart: pStart.x,
|
708
|
+
yStart: pStart.y,
|
709
|
+
xEnd: pEnd.x,
|
710
|
+
yEnd: pEnd.y});
|
711
|
+
|
712
|
+
};
|
713
|
+
|
714
|
+
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
|
715
|
+
this.moveTo(aX, aY);
|
716
|
+
this.lineTo(aX + aWidth, aY);
|
717
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
718
|
+
this.lineTo(aX, aY + aHeight);
|
719
|
+
this.closePath();
|
720
|
+
};
|
721
|
+
|
722
|
+
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
|
723
|
+
var oldPath = this.currentPath_;
|
724
|
+
this.beginPath();
|
725
|
+
|
726
|
+
this.moveTo(aX, aY);
|
727
|
+
this.lineTo(aX + aWidth, aY);
|
728
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
729
|
+
this.lineTo(aX, aY + aHeight);
|
730
|
+
this.closePath();
|
731
|
+
this.stroke();
|
732
|
+
|
733
|
+
this.currentPath_ = oldPath;
|
734
|
+
};
|
735
|
+
|
736
|
+
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
|
737
|
+
var oldPath = this.currentPath_;
|
738
|
+
this.beginPath();
|
739
|
+
|
740
|
+
this.moveTo(aX, aY);
|
741
|
+
this.lineTo(aX + aWidth, aY);
|
742
|
+
this.lineTo(aX + aWidth, aY + aHeight);
|
743
|
+
this.lineTo(aX, aY + aHeight);
|
744
|
+
this.closePath();
|
745
|
+
this.fill();
|
746
|
+
|
747
|
+
this.currentPath_ = oldPath;
|
748
|
+
};
|
749
|
+
|
750
|
+
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
|
751
|
+
var gradient = new CanvasGradient_('gradient');
|
752
|
+
gradient.x0_ = aX0;
|
753
|
+
gradient.y0_ = aY0;
|
754
|
+
gradient.x1_ = aX1;
|
755
|
+
gradient.y1_ = aY1;
|
756
|
+
return gradient;
|
757
|
+
};
|
758
|
+
|
759
|
+
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
|
760
|
+
aX1, aY1, aR1) {
|
761
|
+
var gradient = new CanvasGradient_('gradientradial');
|
762
|
+
gradient.x0_ = aX0;
|
763
|
+
gradient.y0_ = aY0;
|
764
|
+
gradient.r0_ = aR0;
|
765
|
+
gradient.x1_ = aX1;
|
766
|
+
gradient.y1_ = aY1;
|
767
|
+
gradient.r1_ = aR1;
|
768
|
+
return gradient;
|
769
|
+
};
|
770
|
+
|
771
|
+
contextPrototype.drawImage = function(image, var_args) {
|
772
|
+
var dx, dy, dw, dh, sx, sy, sw, sh;
|
773
|
+
|
774
|
+
// to find the original width we overide the width and height
|
775
|
+
var oldRuntimeWidth = image.runtimeStyle.width;
|
776
|
+
var oldRuntimeHeight = image.runtimeStyle.height;
|
777
|
+
image.runtimeStyle.width = 'auto';
|
778
|
+
image.runtimeStyle.height = 'auto';
|
779
|
+
|
780
|
+
// get the original size
|
781
|
+
var w = image.width;
|
782
|
+
var h = image.height;
|
783
|
+
|
784
|
+
// and remove overides
|
785
|
+
image.runtimeStyle.width = oldRuntimeWidth;
|
786
|
+
image.runtimeStyle.height = oldRuntimeHeight;
|
787
|
+
|
788
|
+
if (arguments.length == 3) {
|
789
|
+
dx = arguments[1];
|
790
|
+
dy = arguments[2];
|
791
|
+
sx = sy = 0;
|
792
|
+
sw = dw = w;
|
793
|
+
sh = dh = h;
|
794
|
+
} else if (arguments.length == 5) {
|
795
|
+
dx = arguments[1];
|
796
|
+
dy = arguments[2];
|
797
|
+
dw = arguments[3];
|
798
|
+
dh = arguments[4];
|
799
|
+
sx = sy = 0;
|
800
|
+
sw = w;
|
801
|
+
sh = h;
|
802
|
+
} else if (arguments.length == 9) {
|
803
|
+
sx = arguments[1];
|
804
|
+
sy = arguments[2];
|
805
|
+
sw = arguments[3];
|
806
|
+
sh = arguments[4];
|
807
|
+
dx = arguments[5];
|
808
|
+
dy = arguments[6];
|
809
|
+
dw = arguments[7];
|
810
|
+
dh = arguments[8];
|
811
|
+
} else {
|
812
|
+
throw Error('Invalid number of arguments');
|
813
|
+
}
|
814
|
+
|
815
|
+
var d = getCoords(this, dx, dy);
|
816
|
+
|
817
|
+
var w2 = sw / 2;
|
818
|
+
var h2 = sh / 2;
|
819
|
+
|
820
|
+
var vmlStr = [];
|
821
|
+
|
822
|
+
var W = 10;
|
823
|
+
var H = 10;
|
824
|
+
|
825
|
+
// For some reason that I've now forgotten, using divs didn't work
|
826
|
+
vmlStr.push(' <g_vml_:group',
|
827
|
+
' coordsize="', Z * W, ',', Z * H, '"',
|
828
|
+
' coordorigin="0,0"' ,
|
829
|
+
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
|
830
|
+
|
831
|
+
// If filters are necessary (rotation exists), create them
|
832
|
+
// filters are bog-slow, so only create them if abbsolutely necessary
|
833
|
+
// The following check doesn't account for skews (which don't exist
|
834
|
+
// in the canvas spec (yet) anyway.
|
835
|
+
|
836
|
+
if (this.m_[0][0] != 1 || this.m_[0][1] ||
|
837
|
+
this.m_[1][1] != 1 || this.m_[1][0]) {
|
838
|
+
var filter = [];
|
839
|
+
|
840
|
+
// Note the 12/21 reversal
|
841
|
+
filter.push('M11=', this.m_[0][0], ',',
|
842
|
+
'M12=', this.m_[1][0], ',',
|
843
|
+
'M21=', this.m_[0][1], ',',
|
844
|
+
'M22=', this.m_[1][1], ',',
|
845
|
+
'Dx=', mr(d.x / Z), ',',
|
846
|
+
'Dy=', mr(d.y / Z), '');
|
847
|
+
|
848
|
+
// Bounding box calculation (need to minimize displayed area so that
|
849
|
+
// filters don't waste time on unused pixels.
|
850
|
+
var max = d;
|
851
|
+
var c2 = getCoords(this, dx + dw, dy);
|
852
|
+
var c3 = getCoords(this, dx, dy + dh);
|
853
|
+
var c4 = getCoords(this, dx + dw, dy + dh);
|
854
|
+
|
855
|
+
max.x = m.max(max.x, c2.x, c3.x, c4.x);
|
856
|
+
max.y = m.max(max.y, c2.y, c3.y, c4.y);
|
857
|
+
|
858
|
+
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
|
859
|
+
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
|
860
|
+
filter.join(''), ", sizingmethod='clip');");
|
861
|
+
|
862
|
+
} else {
|
863
|
+
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
|
864
|
+
}
|
865
|
+
|
866
|
+
vmlStr.push(' ">' ,
|
867
|
+
'<g_vml_:image src="', image.src, '"',
|
868
|
+
' style="width:', Z * dw, 'px;',
|
869
|
+
' height:', Z * dh, 'px"',
|
870
|
+
' cropleft="', sx / w, '"',
|
871
|
+
' croptop="', sy / h, '"',
|
872
|
+
' cropright="', (w - sx - sw) / w, '"',
|
873
|
+
' cropbottom="', (h - sy - sh) / h, '"',
|
874
|
+
' />',
|
875
|
+
'</g_vml_:group>');
|
876
|
+
|
877
|
+
this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
|
878
|
+
};
|
879
|
+
|
880
|
+
contextPrototype.stroke = function(aFill) {
|
881
|
+
var W = 10;
|
882
|
+
var H = 10;
|
883
|
+
// Divide the shape into chunks if it's too long because IE has a limit
|
884
|
+
// somewhere for how long a VML shape can be. This simple division does
|
885
|
+
// not work with fills, only strokes, unfortunately.
|
886
|
+
var chunkSize = 5000;
|
887
|
+
|
888
|
+
var min = {x: null, y: null};
|
889
|
+
var max = {x: null, y: null};
|
890
|
+
|
891
|
+
for (var j = 0; j < this.currentPath_.length; j += chunkSize) {
|
892
|
+
var lineStr = [];
|
893
|
+
var lineOpen = false;
|
894
|
+
|
895
|
+
lineStr.push('<g_vml_:shape',
|
896
|
+
' filled="', !!aFill, '"',
|
897
|
+
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
|
898
|
+
' coordorigin="0,0"',
|
899
|
+
' coordsize="', Z * W, ',', Z * H, '"',
|
900
|
+
' stroked="', !aFill, '"',
|
901
|
+
' path="');
|
902
|
+
|
903
|
+
var newSeq = false;
|
904
|
+
|
905
|
+
for (var i = j; i < Math.min(j + chunkSize, this.currentPath_.length); i++) {
|
906
|
+
if (i % chunkSize == 0 && i > 0) { // move into position for next chunk
|
907
|
+
lineStr.push(' m ', mr(this.currentPath_[i-1].x), ',', mr(this.currentPath_[i-1].y));
|
908
|
+
}
|
909
|
+
|
910
|
+
var p = this.currentPath_[i];
|
911
|
+
var c;
|
912
|
+
|
913
|
+
switch (p.type) {
|
914
|
+
case 'moveTo':
|
915
|
+
c = p;
|
916
|
+
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
|
917
|
+
break;
|
918
|
+
case 'lineTo':
|
919
|
+
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
|
920
|
+
break;
|
921
|
+
case 'close':
|
922
|
+
lineStr.push(' x ');
|
923
|
+
p = null;
|
924
|
+
break;
|
925
|
+
case 'bezierCurveTo':
|
926
|
+
lineStr.push(' c ',
|
927
|
+
mr(p.cp1x), ',', mr(p.cp1y), ',',
|
928
|
+
mr(p.cp2x), ',', mr(p.cp2y), ',',
|
929
|
+
mr(p.x), ',', mr(p.y));
|
930
|
+
break;
|
931
|
+
case 'at':
|
932
|
+
case 'wa':
|
933
|
+
lineStr.push(' ', p.type, ' ',
|
934
|
+
mr(p.x - this.arcScaleX_ * p.radius), ',',
|
935
|
+
mr(p.y - this.arcScaleY_ * p.radius), ' ',
|
936
|
+
mr(p.x + this.arcScaleX_ * p.radius), ',',
|
937
|
+
mr(p.y + this.arcScaleY_ * p.radius), ' ',
|
938
|
+
mr(p.xStart), ',', mr(p.yStart), ' ',
|
939
|
+
mr(p.xEnd), ',', mr(p.yEnd));
|
940
|
+
break;
|
941
|
+
}
|
942
|
+
|
943
|
+
|
944
|
+
// TODO: Following is broken for curves due to
|
945
|
+
// move to proper paths.
|
946
|
+
|
947
|
+
// Figure out dimensions so we can do gradient fills
|
948
|
+
// properly
|
949
|
+
if (p) {
|
950
|
+
if (min.x == null || p.x < min.x) {
|
951
|
+
min.x = p.x;
|
952
|
+
}
|
953
|
+
if (max.x == null || p.x > max.x) {
|
954
|
+
max.x = p.x;
|
955
|
+
}
|
956
|
+
if (min.y == null || p.y < min.y) {
|
957
|
+
min.y = p.y;
|
958
|
+
}
|
959
|
+
if (max.y == null || p.y > max.y) {
|
960
|
+
max.y = p.y;
|
961
|
+
}
|
962
|
+
}
|
963
|
+
}
|
964
|
+
lineStr.push(' ">');
|
965
|
+
|
966
|
+
if (!aFill) {
|
967
|
+
appendStroke(this, lineStr);
|
968
|
+
} else {
|
969
|
+
appendFill(this, lineStr, min, max);
|
970
|
+
}
|
971
|
+
|
972
|
+
lineStr.push('</g_vml_:shape>');
|
973
|
+
|
974
|
+
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
975
|
+
}
|
976
|
+
};
|
977
|
+
|
978
|
+
function appendStroke(ctx, lineStr) {
|
979
|
+
var a = processStyle(ctx.strokeStyle);
|
980
|
+
var color = a.color;
|
981
|
+
var opacity = a.alpha * ctx.globalAlpha;
|
982
|
+
var lineWidth = ctx.lineScale_ * ctx.lineWidth;
|
983
|
+
|
984
|
+
// VML cannot correctly render a line if the width is less than 1px.
|
985
|
+
// In that case, we dilute the color to make the line look thinner.
|
986
|
+
if (lineWidth < 1) {
|
987
|
+
opacity *= lineWidth;
|
988
|
+
}
|
989
|
+
|
990
|
+
lineStr.push(
|
991
|
+
'<g_vml_:stroke',
|
992
|
+
' opacity="', opacity, '"',
|
993
|
+
' joinstyle="', ctx.lineJoin, '"',
|
994
|
+
' miterlimit="', ctx.miterLimit, '"',
|
995
|
+
' endcap="', processLineCap(ctx.lineCap), '"',
|
996
|
+
' weight="', lineWidth, 'px"',
|
997
|
+
' color="', color, '" />'
|
998
|
+
);
|
999
|
+
}
|
1000
|
+
|
1001
|
+
function appendFill(ctx, lineStr, min, max) {
|
1002
|
+
var fillStyle = ctx.fillStyle;
|
1003
|
+
var arcScaleX = ctx.arcScaleX_;
|
1004
|
+
var arcScaleY = ctx.arcScaleY_;
|
1005
|
+
var width = max.x - min.x;
|
1006
|
+
var height = max.y - min.y;
|
1007
|
+
if (fillStyle instanceof CanvasGradient_) {
|
1008
|
+
// TODO: Gradients transformed with the transformation matrix.
|
1009
|
+
var angle = 0;
|
1010
|
+
var focus = {x: 0, y: 0};
|
1011
|
+
|
1012
|
+
// additional offset
|
1013
|
+
var shift = 0;
|
1014
|
+
// scale factor for offset
|
1015
|
+
var expansion = 1;
|
1016
|
+
|
1017
|
+
if (fillStyle.type_ == 'gradient') {
|
1018
|
+
var x0 = fillStyle.x0_ / arcScaleX;
|
1019
|
+
var y0 = fillStyle.y0_ / arcScaleY;
|
1020
|
+
var x1 = fillStyle.x1_ / arcScaleX;
|
1021
|
+
var y1 = fillStyle.y1_ / arcScaleY;
|
1022
|
+
var p0 = getCoords(ctx, x0, y0);
|
1023
|
+
var p1 = getCoords(ctx, x1, y1);
|
1024
|
+
var dx = p1.x - p0.x;
|
1025
|
+
var dy = p1.y - p0.y;
|
1026
|
+
angle = Math.atan2(dx, dy) * 180 / Math.PI;
|
1027
|
+
|
1028
|
+
// The angle should be a non-negative number.
|
1029
|
+
if (angle < 0) {
|
1030
|
+
angle += 360;
|
1031
|
+
}
|
1032
|
+
|
1033
|
+
// Very small angles produce an unexpected result because they are
|
1034
|
+
// converted to a scientific notation string.
|
1035
|
+
if (angle < 1e-6) {
|
1036
|
+
angle = 0;
|
1037
|
+
}
|
1038
|
+
} else {
|
1039
|
+
var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_);
|
1040
|
+
focus = {
|
1041
|
+
x: (p0.x - min.x) / width,
|
1042
|
+
y: (p0.y - min.y) / height
|
1043
|
+
};
|
1044
|
+
|
1045
|
+
width /= arcScaleX * Z;
|
1046
|
+
height /= arcScaleY * Z;
|
1047
|
+
var dimension = m.max(width, height);
|
1048
|
+
shift = 2 * fillStyle.r0_ / dimension;
|
1049
|
+
expansion = 2 * fillStyle.r1_ / dimension - shift;
|
1050
|
+
}
|
1051
|
+
|
1052
|
+
// We need to sort the color stops in ascending order by offset,
|
1053
|
+
// otherwise IE won't interpret it correctly.
|
1054
|
+
var stops = fillStyle.colors_;
|
1055
|
+
stops.sort(function(cs1, cs2) {
|
1056
|
+
return cs1.offset - cs2.offset;
|
1057
|
+
});
|
1058
|
+
|
1059
|
+
var length = stops.length;
|
1060
|
+
var color1 = stops[0].color;
|
1061
|
+
var color2 = stops[length - 1].color;
|
1062
|
+
var opacity1 = stops[0].alpha * ctx.globalAlpha;
|
1063
|
+
var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
|
1064
|
+
|
1065
|
+
var colors = [];
|
1066
|
+
for (var i = 0; i < length; i++) {
|
1067
|
+
var stop = stops[i];
|
1068
|
+
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
// When colors attribute is used, the meanings of opacity and o:opacity2
|
1072
|
+
// are reversed.
|
1073
|
+
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
|
1074
|
+
' method="none" focus="100%"',
|
1075
|
+
' color="', color1, '"',
|
1076
|
+
' color2="', color2, '"',
|
1077
|
+
' colors="', colors.join(','), '"',
|
1078
|
+
' opacity="', opacity2, '"',
|
1079
|
+
' g_o_:opacity2="', opacity1, '"',
|
1080
|
+
' angle="', angle, '"',
|
1081
|
+
' focusposition="', focus.x, ',', focus.y, '" />');
|
1082
|
+
} else if (fillStyle instanceof CanvasPattern_) {
|
1083
|
+
if (width && height) {
|
1084
|
+
var deltaLeft = -min.x;
|
1085
|
+
var deltaTop = -min.y;
|
1086
|
+
lineStr.push('<g_vml_:fill',
|
1087
|
+
' position="',
|
1088
|
+
deltaLeft / width * arcScaleX * arcScaleX, ',',
|
1089
|
+
deltaTop / height * arcScaleY * arcScaleY, '"',
|
1090
|
+
' type="tile"',
|
1091
|
+
// TODO: Figure out the correct size to fit the scale.
|
1092
|
+
//' size="', w, 'px ', h, 'px"',
|
1093
|
+
' src="', fillStyle.src_, '" />');
|
1094
|
+
}
|
1095
|
+
} else {
|
1096
|
+
var a = processStyle(ctx.fillStyle);
|
1097
|
+
var color = a.color;
|
1098
|
+
var opacity = a.alpha * ctx.globalAlpha;
|
1099
|
+
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
|
1100
|
+
'" />');
|
1101
|
+
}
|
1102
|
+
}
|
1103
|
+
|
1104
|
+
contextPrototype.fill = function() {
|
1105
|
+
this.stroke(true);
|
1106
|
+
};
|
1107
|
+
|
1108
|
+
contextPrototype.closePath = function() {
|
1109
|
+
this.currentPath_.push({type: 'close'});
|
1110
|
+
};
|
1111
|
+
|
1112
|
+
function getCoords(ctx, aX, aY) {
|
1113
|
+
var m = ctx.m_;
|
1114
|
+
return {
|
1115
|
+
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
|
1116
|
+
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
|
1117
|
+
};
|
1118
|
+
};
|
1119
|
+
|
1120
|
+
contextPrototype.save = function() {
|
1121
|
+
var o = {};
|
1122
|
+
copyState(this, o);
|
1123
|
+
this.aStack_.push(o);
|
1124
|
+
this.mStack_.push(this.m_);
|
1125
|
+
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
|
1126
|
+
};
|
1127
|
+
|
1128
|
+
contextPrototype.restore = function() {
|
1129
|
+
if (this.aStack_.length) {
|
1130
|
+
copyState(this.aStack_.pop(), this);
|
1131
|
+
this.m_ = this.mStack_.pop();
|
1132
|
+
}
|
1133
|
+
};
|
1134
|
+
|
1135
|
+
function matrixIsFinite(m) {
|
1136
|
+
return isFinite(m[0][0]) && isFinite(m[0][1]) &&
|
1137
|
+
isFinite(m[1][0]) && isFinite(m[1][1]) &&
|
1138
|
+
isFinite(m[2][0]) && isFinite(m[2][1]);
|
1139
|
+
}
|
1140
|
+
|
1141
|
+
function setM(ctx, m, updateLineScale) {
|
1142
|
+
if (!matrixIsFinite(m)) {
|
1143
|
+
return;
|
1144
|
+
}
|
1145
|
+
ctx.m_ = m;
|
1146
|
+
|
1147
|
+
if (updateLineScale) {
|
1148
|
+
// Get the line scale.
|
1149
|
+
// Determinant of this.m_ means how much the area is enlarged by the
|
1150
|
+
// transformation. So its square root can be used as a scale factor
|
1151
|
+
// for width.
|
1152
|
+
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
|
1153
|
+
ctx.lineScale_ = sqrt(abs(det));
|
1154
|
+
}
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
contextPrototype.translate = function(aX, aY) {
|
1158
|
+
var m1 = [
|
1159
|
+
[1, 0, 0],
|
1160
|
+
[0, 1, 0],
|
1161
|
+
[aX, aY, 1]
|
1162
|
+
];
|
1163
|
+
|
1164
|
+
setM(this, matrixMultiply(m1, this.m_), false);
|
1165
|
+
};
|
1166
|
+
|
1167
|
+
contextPrototype.rotate = function(aRot) {
|
1168
|
+
var c = mc(aRot);
|
1169
|
+
var s = ms(aRot);
|
1170
|
+
|
1171
|
+
var m1 = [
|
1172
|
+
[c, s, 0],
|
1173
|
+
[-s, c, 0],
|
1174
|
+
[0, 0, 1]
|
1175
|
+
];
|
1176
|
+
|
1177
|
+
setM(this, matrixMultiply(m1, this.m_), false);
|
1178
|
+
};
|
1179
|
+
|
1180
|
+
contextPrototype.scale = function(aX, aY) {
|
1181
|
+
this.arcScaleX_ *= aX;
|
1182
|
+
this.arcScaleY_ *= aY;
|
1183
|
+
var m1 = [
|
1184
|
+
[aX, 0, 0],
|
1185
|
+
[0, aY, 0],
|
1186
|
+
[0, 0, 1]
|
1187
|
+
];
|
1188
|
+
|
1189
|
+
setM(this, matrixMultiply(m1, this.m_), true);
|
1190
|
+
};
|
1191
|
+
|
1192
|
+
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
|
1193
|
+
var m1 = [
|
1194
|
+
[m11, m12, 0],
|
1195
|
+
[m21, m22, 0],
|
1196
|
+
[dx, dy, 1]
|
1197
|
+
];
|
1198
|
+
|
1199
|
+
setM(this, matrixMultiply(m1, this.m_), true);
|
1200
|
+
};
|
1201
|
+
|
1202
|
+
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
|
1203
|
+
var m = [
|
1204
|
+
[m11, m12, 0],
|
1205
|
+
[m21, m22, 0],
|
1206
|
+
[dx, dy, 1]
|
1207
|
+
];
|
1208
|
+
|
1209
|
+
setM(this, m, true);
|
1210
|
+
};
|
1211
|
+
|
1212
|
+
/**
|
1213
|
+
* The text drawing function.
|
1214
|
+
* The maxWidth argument isn't taken in account, since no browser supports
|
1215
|
+
* it yet.
|
1216
|
+
*/
|
1217
|
+
contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
|
1218
|
+
var m = this.m_,
|
1219
|
+
delta = 1000,
|
1220
|
+
left = 0,
|
1221
|
+
right = delta,
|
1222
|
+
offset = {x: 0, y: 0},
|
1223
|
+
lineStr = [];
|
1224
|
+
|
1225
|
+
var fontStyle = getComputedStyle(processFontStyle(this.font),
|
1226
|
+
this.element_);
|
1227
|
+
|
1228
|
+
var fontStyleString = buildStyle(fontStyle);
|
1229
|
+
|
1230
|
+
var elementStyle = this.element_.currentStyle;
|
1231
|
+
var textAlign = this.textAlign.toLowerCase();
|
1232
|
+
switch (textAlign) {
|
1233
|
+
case 'left':
|
1234
|
+
case 'center':
|
1235
|
+
case 'right':
|
1236
|
+
break;
|
1237
|
+
case 'end':
|
1238
|
+
textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
|
1239
|
+
break;
|
1240
|
+
case 'start':
|
1241
|
+
textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
|
1242
|
+
break;
|
1243
|
+
default:
|
1244
|
+
textAlign = 'left';
|
1245
|
+
}
|
1246
|
+
|
1247
|
+
// 1.75 is an arbitrary number, as there is no info about the text baseline
|
1248
|
+
switch (this.textBaseline) {
|
1249
|
+
case 'hanging':
|
1250
|
+
case 'top':
|
1251
|
+
offset.y = fontStyle.size / 1.75;
|
1252
|
+
break;
|
1253
|
+
case 'middle':
|
1254
|
+
break;
|
1255
|
+
default:
|
1256
|
+
case null:
|
1257
|
+
case 'alphabetic':
|
1258
|
+
case 'ideographic':
|
1259
|
+
case 'bottom':
|
1260
|
+
offset.y = -fontStyle.size / 2.25;
|
1261
|
+
break;
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
switch(textAlign) {
|
1265
|
+
case 'right':
|
1266
|
+
left = delta;
|
1267
|
+
right = 0.05;
|
1268
|
+
break;
|
1269
|
+
case 'center':
|
1270
|
+
left = right = delta / 2;
|
1271
|
+
break;
|
1272
|
+
}
|
1273
|
+
|
1274
|
+
var d = getCoords(this, x + offset.x, y + offset.y);
|
1275
|
+
|
1276
|
+
lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
|
1277
|
+
' coordsize="100 100" coordorigin="0 0"',
|
1278
|
+
' filled="', !stroke, '" stroked="', !!stroke,
|
1279
|
+
'" style="position:absolute;width:1px;height:1px;">');
|
1280
|
+
|
1281
|
+
if (stroke) {
|
1282
|
+
appendStroke(this, lineStr);
|
1283
|
+
} else {
|
1284
|
+
// TODO: Fix the min and max params.
|
1285
|
+
appendFill(this, lineStr, {x: -left, y: 0},
|
1286
|
+
{x: right, y: fontStyle.size});
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
|
1290
|
+
m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
|
1291
|
+
|
1292
|
+
var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
|
1293
|
+
|
1294
|
+
lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
|
1295
|
+
' offset="', skewOffset, '" origin="', left ,' 0" />',
|
1296
|
+
'<g_vml_:path textpathok="true" />',
|
1297
|
+
'<g_vml_:textpath on="true" string="',
|
1298
|
+
encodeHtmlAttribute(text),
|
1299
|
+
'" style="v-text-align:', textAlign,
|
1300
|
+
';font:', encodeHtmlAttribute(fontStyleString),
|
1301
|
+
'" /></g_vml_:line>');
|
1302
|
+
|
1303
|
+
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
|
1304
|
+
};
|
1305
|
+
|
1306
|
+
contextPrototype.fillText = function(text, x, y, maxWidth) {
|
1307
|
+
this.drawText_(text, x, y, maxWidth, false);
|
1308
|
+
};
|
1309
|
+
|
1310
|
+
contextPrototype.strokeText = function(text, x, y, maxWidth) {
|
1311
|
+
this.drawText_(text, x, y, maxWidth, true);
|
1312
|
+
};
|
1313
|
+
|
1314
|
+
contextPrototype.measureText = function(text) {
|
1315
|
+
if (!this.textMeasureEl_) {
|
1316
|
+
var s = '<span style="position:absolute;' +
|
1317
|
+
'top:-20000px;left:0;padding:0;margin:0;border:none;' +
|
1318
|
+
'white-space:pre;"></span>';
|
1319
|
+
this.element_.insertAdjacentHTML('beforeEnd', s);
|
1320
|
+
this.textMeasureEl_ = this.element_.lastChild;
|
1321
|
+
}
|
1322
|
+
var doc = this.element_.ownerDocument;
|
1323
|
+
this.textMeasureEl_.innerHTML = '';
|
1324
|
+
this.textMeasureEl_.style.font = this.font;
|
1325
|
+
// Don't use innerHTML or innerText because they allow markup/whitespace.
|
1326
|
+
this.textMeasureEl_.appendChild(doc.createTextNode(text));
|
1327
|
+
return {width: this.textMeasureEl_.offsetWidth};
|
1328
|
+
};
|
1329
|
+
|
1330
|
+
/******** STUBS ********/
|
1331
|
+
contextPrototype.clip = function() {
|
1332
|
+
// TODO: Implement
|
1333
|
+
};
|
1334
|
+
|
1335
|
+
contextPrototype.arcTo = function() {
|
1336
|
+
// TODO: Implement
|
1337
|
+
};
|
1338
|
+
|
1339
|
+
contextPrototype.createPattern = function(image, repetition) {
|
1340
|
+
return new CanvasPattern_(image, repetition);
|
1341
|
+
};
|
1342
|
+
|
1343
|
+
// Gradient / Pattern Stubs
|
1344
|
+
function CanvasGradient_(aType) {
|
1345
|
+
this.type_ = aType;
|
1346
|
+
this.x0_ = 0;
|
1347
|
+
this.y0_ = 0;
|
1348
|
+
this.r0_ = 0;
|
1349
|
+
this.x1_ = 0;
|
1350
|
+
this.y1_ = 0;
|
1351
|
+
this.r1_ = 0;
|
1352
|
+
this.colors_ = [];
|
1353
|
+
}
|
1354
|
+
|
1355
|
+
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
|
1356
|
+
aColor = processStyle(aColor);
|
1357
|
+
this.colors_.push({offset: aOffset,
|
1358
|
+
color: aColor.color,
|
1359
|
+
alpha: aColor.alpha});
|
1360
|
+
};
|
1361
|
+
|
1362
|
+
function CanvasPattern_(image, repetition) {
|
1363
|
+
assertImageIsValid(image);
|
1364
|
+
switch (repetition) {
|
1365
|
+
case 'repeat':
|
1366
|
+
case null:
|
1367
|
+
case '':
|
1368
|
+
this.repetition_ = 'repeat';
|
1369
|
+
break
|
1370
|
+
case 'repeat-x':
|
1371
|
+
case 'repeat-y':
|
1372
|
+
case 'no-repeat':
|
1373
|
+
this.repetition_ = repetition;
|
1374
|
+
break;
|
1375
|
+
default:
|
1376
|
+
throwException('SYNTAX_ERR');
|
1377
|
+
}
|
1378
|
+
|
1379
|
+
this.src_ = image.src;
|
1380
|
+
this.width_ = image.width;
|
1381
|
+
this.height_ = image.height;
|
1382
|
+
}
|
1383
|
+
|
1384
|
+
function throwException(s) {
|
1385
|
+
throw new DOMException_(s);
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
function assertImageIsValid(img) {
|
1389
|
+
if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
|
1390
|
+
throwException('TYPE_MISMATCH_ERR');
|
1391
|
+
}
|
1392
|
+
if (img.readyState != 'complete') {
|
1393
|
+
throwException('INVALID_STATE_ERR');
|
1394
|
+
}
|
1395
|
+
}
|
1396
|
+
|
1397
|
+
function DOMException_(s) {
|
1398
|
+
this.code = this[s];
|
1399
|
+
this.message = s +': DOM Exception ' + this.code;
|
1400
|
+
}
|
1401
|
+
var p = DOMException_.prototype = new Error;
|
1402
|
+
p.INDEX_SIZE_ERR = 1;
|
1403
|
+
p.DOMSTRING_SIZE_ERR = 2;
|
1404
|
+
p.HIERARCHY_REQUEST_ERR = 3;
|
1405
|
+
p.WRONG_DOCUMENT_ERR = 4;
|
1406
|
+
p.INVALID_CHARACTER_ERR = 5;
|
1407
|
+
p.NO_DATA_ALLOWED_ERR = 6;
|
1408
|
+
p.NO_MODIFICATION_ALLOWED_ERR = 7;
|
1409
|
+
p.NOT_FOUND_ERR = 8;
|
1410
|
+
p.NOT_SUPPORTED_ERR = 9;
|
1411
|
+
p.INUSE_ATTRIBUTE_ERR = 10;
|
1412
|
+
p.INVALID_STATE_ERR = 11;
|
1413
|
+
p.SYNTAX_ERR = 12;
|
1414
|
+
p.INVALID_MODIFICATION_ERR = 13;
|
1415
|
+
p.NAMESPACE_ERR = 14;
|
1416
|
+
p.INVALID_ACCESS_ERR = 15;
|
1417
|
+
p.VALIDATION_ERR = 16;
|
1418
|
+
p.TYPE_MISMATCH_ERR = 17;
|
1419
|
+
|
1420
|
+
// set up externs
|
1421
|
+
G_vmlCanvasManager = G_vmlCanvasManager_;
|
1422
|
+
CanvasRenderingContext2D = CanvasRenderingContext2D_;
|
1423
|
+
CanvasGradient = CanvasGradient_;
|
1424
|
+
CanvasPattern = CanvasPattern_;
|
1425
|
+
DOMException = DOMException_;
|
1426
|
+
})();
|
1427
|
+
|
1428
|
+
} // if
|