diff --git a/LICENCE b/LICENCE index 4acf216c70..4921a6055a 100644 --- a/LICENCE +++ b/LICENCE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2017 Sergey Rybalkin +Copyright (c) 2016-2018 Sergey Rybalkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ac8d226979..eb2a18210c 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,11 @@ [![Build Status](https://travis-ci.org/rybalkinsd/atom.png?branch=master)](https://travis-ci.org/rybalkinsd/atom) +[![](http://icons.iconarchive.com/icons/dakirby309/simply-styled/32/YouTube-icon.png) Youtube channel](https://www.youtube.com/playlist?list=PLrCZzMib1e9pnFbVV3u4s7ki5NTnm7WgT) - watch course videos -[![](http://icons.iconarchive.com/icons/alecive/flatwoken/32/Apps-Telegram-icon.png) Join chat](https://t.me/joinchat/AAAAAEF63F9PvqE4JDzYdQ) - feel free to contact us -[![](http://icons.iconarchive.com/icons/dakirby309/simply-styled/32/YouTube-icon.png) Youtube channel](https://www.youtube.com/playlist?list=PLrCZzMib1e9pnFbVV3u4s7ki5NTnm7WgT) +[![](http://icons.iconarchive.com/icons/alecive/flatwoken/32/Apps-Telegram-icon.png) Join chat](https://t.me/joinchat/AAISfEF63F8pPTObTsrR9w) - feel free to contact us Course repository. All course lectures/sources/homeworks are available here. - - -[![Course announcement](https://img.youtube.com/vi/12Ur1brHHz8/0.jpg)](https://www.youtube.com/watch?v=12Ur1brHHz8&feature=youtu.be "Course announcement") ## Lectures list: [Lecture 1. Basics, git](https://gitpitch.com/rybalkinsd/atom/lecture01?grs=github&t=white&p=lecture01%2Fpresentation#/) diff --git a/bomberman/.DS_Store b/bomberman/.DS_Store deleted file mode 100644 index 2b8883c189..0000000000 Binary files a/bomberman/.DS_Store and /dev/null differ diff --git a/bomberman/frontend/.DS_Store b/bomberman/frontend/.DS_Store deleted file mode 100644 index 81229e8d26..0000000000 Binary files a/bomberman/frontend/.DS_Store and /dev/null differ diff --git a/bomberman/frontend/Dockerfile b/bomberman/frontend/Dockerfile deleted file mode 100644 index ae387ba8c4..0000000000 --- a/bomberman/frontend/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM jetty:9.4.5-alpine -MAINTAINER Alex Pomosov -ADD ./build/libs/bomberman/*.war /var/lib/jetty/webapps/ROOT.war -EXPOSE 8080 \ No newline at end of file diff --git a/bomberman/frontend/build.gradle b/bomberman/frontend/build.gradle deleted file mode 100644 index d3b21134c0..0000000000 --- a/bomberman/frontend/build.gradle +++ /dev/null @@ -1 +0,0 @@ -apply plugin: 'war' diff --git a/bomberman/frontend/build/libs/bomberman/frontend-1.0-SNAPSHOT.war b/bomberman/frontend/build/libs/bomberman/frontend-1.0-SNAPSHOT.war deleted file mode 100644 index 6355eaa29b..0000000000 Binary files a/bomberman/frontend/build/libs/bomberman/frontend-1.0-SNAPSHOT.war and /dev/null differ diff --git a/bomberman/frontend/build/tmp/war/MANIFEST.MF b/bomberman/frontend/build/tmp/war/MANIFEST.MF deleted file mode 100644 index 58630c02ef..0000000000 --- a/bomberman/frontend/build/tmp/war/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/bomberman/frontend/src/.DS_Store b/bomberman/frontend/src/.DS_Store deleted file mode 100644 index 254fc3aa65..0000000000 Binary files a/bomberman/frontend/src/.DS_Store and /dev/null differ diff --git a/bomberman/frontend/src/main/.DS_Store b/bomberman/frontend/src/main/.DS_Store deleted file mode 100644 index ec10f69338..0000000000 Binary files a/bomberman/frontend/src/main/.DS_Store and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/README.md b/bomberman/frontend/src/main/webapp/README.md deleted file mode 100644 index 529b54b080..0000000000 --- a/bomberman/frontend/src/main/webapp/README.md +++ /dev/null @@ -1,5 +0,0 @@ -This frontend is developed by: -- One-hand frontend developer -- QA specialist with mental dysfunction - -Enjoy, your [gojava](http://gojava.com) team. \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/css/bootstrap.css b/bomberman/frontend/src/main/webapp/css/bootstrap.css deleted file mode 100644 index 6167622cec..0000000000 --- a/bomberman/frontend/src/main/webapp/css/bootstrap.css +++ /dev/null @@ -1,6757 +0,0 @@ -/*! - * Bootstrap v3.3.7 (http://getbootstrap.com) - * Copyright 2011-2016 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ -html { - font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} -body { - margin: 0; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline: 0; -} -abbr[title] { - border-bottom: 1px dotted; -} -b, -strong { - font-weight: bold; -} -dfn { - font-style: italic; -} -h1 { - margin: .67em 0; - font-size: 2em; -} -mark { - color: #000; - background: #ff0; -} -small { - font-size: 80%; -} -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} -sup { - top: -.5em; -} -sub { - bottom: -.25em; -} -img { - border: 0; -} -svg:not(:root) { - overflow: hidden; -} -figure { - margin: 1em 40px; -} -hr { - height: 0; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -pre { - overflow: auto; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -button, -input, -optgroup, -select, -textarea { - margin: 0; - font: inherit; - color: inherit; -} -button { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -button[disabled], -html input[disabled] { - cursor: default; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - padding: 0; - border: 0; -} -input { - line-height: normal; -} -input[type="checkbox"], -input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; -} -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -fieldset { - padding: .35em .625em .75em; - margin: 0 2px; - border: 1px solid #c0c0c0; -} -legend { - padding: 0; - border: 0; -} -textarea { - overflow: auto; -} -optgroup { - font-weight: bold; -} -table { - border-spacing: 0; - border-collapse: collapse; -} -td, -th { - padding: 0; -} -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, - *:before, - *:after { - color: #000 !important; - text-shadow: none !important; - background: transparent !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - a[href^="#"]:after, - a[href^="javascript:"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - .navbar { - display: none; - } - .btn > .caret, - .dropup > .btn > .caret { - border-top-color: #000 !important; - } - .label { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table td, - .table th { - background-color: #fff !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #ddd !important; - } -} -@font-face { - font-family: 'Glyphicons Halflings'; - - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\002a"; -} -.glyphicon-plus:before { - content: "\002b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -.glyphicon-cd:before { - content: "\e201"; -} -.glyphicon-save-file:before { - content: "\e202"; -} -.glyphicon-open-file:before { - content: "\e203"; -} -.glyphicon-level-up:before { - content: "\e204"; -} -.glyphicon-copy:before { - content: "\e205"; -} -.glyphicon-paste:before { - content: "\e206"; -} -.glyphicon-alert:before { - content: "\e209"; -} -.glyphicon-equalizer:before { - content: "\e210"; -} -.glyphicon-king:before { - content: "\e211"; -} -.glyphicon-queen:before { - content: "\e212"; -} -.glyphicon-pawn:before { - content: "\e213"; -} -.glyphicon-bishop:before { - content: "\e214"; -} -.glyphicon-knight:before { - content: "\e215"; -} -.glyphicon-baby-formula:before { - content: "\e216"; -} -.glyphicon-tent:before { - content: "\26fa"; -} -.glyphicon-blackboard:before { - content: "\e218"; -} -.glyphicon-bed:before { - content: "\e219"; -} -.glyphicon-apple:before { - content: "\f8ff"; -} -.glyphicon-erase:before { - content: "\e221"; -} -.glyphicon-hourglass:before { - content: "\231b"; -} -.glyphicon-lamp:before { - content: "\e223"; -} -.glyphicon-duplicate:before { - content: "\e224"; -} -.glyphicon-piggy-bank:before { - content: "\e225"; -} -.glyphicon-scissors:before { - content: "\e226"; -} -.glyphicon-bitcoin:before { - content: "\e227"; -} -.glyphicon-btc:before { - content: "\e227"; -} -.glyphicon-xbt:before { - content: "\e227"; -} -.glyphicon-yen:before { - content: "\00a5"; -} -.glyphicon-jpy:before { - content: "\00a5"; -} -.glyphicon-ruble:before { - content: "\20bd"; -} -.glyphicon-rub:before { - content: "\20bd"; -} -.glyphicon-scale:before { - content: "\e230"; -} -.glyphicon-ice-lolly:before { - content: "\e231"; -} -.glyphicon-ice-lolly-tasted:before { - content: "\e232"; -} -.glyphicon-education:before { - content: "\e233"; -} -.glyphicon-option-horizontal:before { - content: "\e234"; -} -.glyphicon-option-vertical:before { - content: "\e235"; -} -.glyphicon-menu-hamburger:before { - content: "\e236"; -} -.glyphicon-modal-window:before { - content: "\e237"; -} -.glyphicon-oil:before { - content: "\e238"; -} -.glyphicon-grain:before { - content: "\e239"; -} -.glyphicon-sunglasses:before { - content: "\e240"; -} -.glyphicon-text-size:before { - content: "\e241"; -} -.glyphicon-text-color:before { - content: "\e242"; -} -.glyphicon-text-background:before { - content: "\e243"; -} -.glyphicon-object-align-top:before { - content: "\e244"; -} -.glyphicon-object-align-bottom:before { - content: "\e245"; -} -.glyphicon-object-align-horizontal:before { - content: "\e246"; -} -.glyphicon-object-align-left:before { - content: "\e247"; -} -.glyphicon-object-align-vertical:before { - content: "\e248"; -} -.glyphicon-object-align-right:before { - content: "\e249"; -} -.glyphicon-triangle-right:before { - content: "\e250"; -} -.glyphicon-triangle-left:before { - content: "\e251"; -} -.glyphicon-triangle-bottom:before { - content: "\e252"; -} -.glyphicon-triangle-top:before { - content: "\e253"; -} -.glyphicon-console:before { - content: "\e254"; -} -.glyphicon-superscript:before { - content: "\e255"; -} -.glyphicon-subscript:before { - content: "\e256"; -} -.glyphicon-menu-left:before { - content: "\e257"; -} -.glyphicon-menu-right:before { - content: "\e258"; -} -.glyphicon-menu-down:before { - content: "\e259"; -} -.glyphicon-menu-up:before { - content: "\e260"; -} -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -html { - font-size: 10px; - - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #333; - background-color: #fff; -} -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} -a { - color: #337ab7; - text-decoration: none; -} -a:hover, -a:focus { - color: #23527c; - text-decoration: underline; -} -a:focus { - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -figure { - margin: 0; -} -img { - vertical-align: middle; -} -.img-responsive, -.thumbnail > img, -.thumbnail a > img, -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - display: block; - max-width: 100%; - height: auto; -} -.img-rounded { - border-radius: 6px; -} -.img-thumbnail { - display: inline-block; - max-width: 100%; - height: auto; - padding: 4px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: all .2s ease-in-out; - -o-transition: all .2s ease-in-out; - transition: all .2s ease-in-out; -} -.img-circle { - border-radius: 50%; -} -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eee; -} -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} -.sr-only-focusable:active, -.sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} -[role="button"] { - cursor: pointer; -} -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #777; -} -h1, -.h1, -h2, -.h2, -h3, -.h3 { - margin-top: 20px; - margin-bottom: 10px; -} -h1 small, -.h1 small, -h2 small, -.h2 small, -h3 small, -.h3 small, -h1 .small, -.h1 .small, -h2 .small, -.h2 .small, -h3 .small, -.h3 .small { - font-size: 65%; -} -h4, -.h4, -h5, -.h5, -h6, -.h6 { - margin-top: 10px; - margin-bottom: 10px; -} -h4 small, -.h4 small, -h5 small, -.h5 small, -h6 small, -.h6 small, -h4 .small, -.h4 .small, -h5 .small, -.h5 .small, -h6 .small, -.h6 .small { - font-size: 75%; -} -h1, -.h1 { - font-size: 36px; -} -h2, -.h2 { - font-size: 30px; -} -h3, -.h3 { - font-size: 24px; -} -h4, -.h4 { - font-size: 18px; -} -h5, -.h5 { - font-size: 14px; -} -h6, -.h6 { - font-size: 12px; -} -p { - margin: 0 0 10px; -} -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4; -} -@media (min-width: 768px) { - .lead { - font-size: 21px; - } -} -small, -.small { - font-size: 85%; -} -mark, -.mark { - padding: .2em; - background-color: #fcf8e3; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.text-justify { - text-align: justify; -} -.text-nowrap { - white-space: nowrap; -} -.text-lowercase { - text-transform: lowercase; -} -.text-uppercase { - text-transform: uppercase; -} -.text-capitalize { - text-transform: capitalize; -} -.text-muted { - color: #777; -} -.text-primary { - color: #337ab7; -} -a.text-primary:hover, -a.text-primary:focus { - color: #286090; -} -.text-success { - color: #3c763d; -} -a.text-success:hover, -a.text-success:focus { - color: #2b542c; -} -.text-info { - color: #31708f; -} -a.text-info:hover, -a.text-info:focus { - color: #245269; -} -.text-warning { - color: #8a6d3b; -} -a.text-warning:hover, -a.text-warning:focus { - color: #66512c; -} -.text-danger { - color: #a94442; -} -a.text-danger:hover, -a.text-danger:focus { - color: #843534; -} -.bg-primary { - color: #fff; - background-color: #337ab7; -} -a.bg-primary:hover, -a.bg-primary:focus { - background-color: #286090; -} -.bg-success { - background-color: #dff0d8; -} -a.bg-success:hover, -a.bg-success:focus { - background-color: #c1e2b3; -} -.bg-info { - background-color: #d9edf7; -} -a.bg-info:hover, -a.bg-info:focus { - background-color: #afd9ee; -} -.bg-warning { - background-color: #fcf8e3; -} -a.bg-warning:hover, -a.bg-warning:focus { - background-color: #f7ecb5; -} -.bg-danger { - background-color: #f2dede; -} -a.bg-danger:hover, -a.bg-danger:focus { - background-color: #e4b9b9; -} -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eee; -} -ul, -ol { - margin-top: 0; - margin-bottom: 10px; -} -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} -.list-unstyled { - padding-left: 0; - list-style: none; -} -.list-inline { - padding-left: 0; - margin-left: -5px; - list-style: none; -} -.list-inline > li { - display: inline-block; - padding-right: 5px; - padding-left: 5px; -} -dl { - margin-top: 0; - margin-bottom: 20px; -} -dt, -dd { - line-height: 1.42857143; -} -dt { - font-weight: bold; -} -dd { - margin-left: 0; -} -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #777; -} -.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #eee; -} -blockquote p:last-child, -blockquote ul:last-child, -blockquote ol:last-child { - margin-bottom: 0; -} -blockquote footer, -blockquote small, -blockquote .small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #777; -} -blockquote footer:before, -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} -.blockquote-reverse, -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - text-align: right; - border-right: 5px solid #eee; - border-left: 0; -} -.blockquote-reverse footer:before, -blockquote.pull-right footer:before, -.blockquote-reverse small:before, -blockquote.pull-right small:before, -.blockquote-reverse .small:before, -blockquote.pull-right .small:before { - content: ''; -} -.blockquote-reverse footer:after, -blockquote.pull-right footer:after, -.blockquote-reverse small:after, -blockquote.pull-right small:after, -.blockquote-reverse .small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143; -} -code, -kbd, -pre, -samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 4px; -} -kbd { - padding: 2px 4px; - font-size: 90%; - color: #fff; - background-color: #333; - border-radius: 3px; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); -} -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: bold; - -webkit-box-shadow: none; - box-shadow: none; -} -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857143; - color: #333; - word-break: break-all; - word-wrap: break-word; - background-color: #f5f5f5; - border: 1px solid #ccc; - border-radius: 4px; -} -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0; -} -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} -.container { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -@media (min-width: 768px) { - .container { - width: 750px; - } -} -@media (min-width: 992px) { - .container { - width: 970px; - } -} -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} -.container-fluid { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -.row { - margin-right: -15px; - margin-left: -15px; -} -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { - position: relative; - min-height: 1px; - padding-right: 15px; - padding-left: 15px; -} -.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { - float: left; -} -.col-xs-12 { - width: 100%; -} -.col-xs-11 { - width: 91.66666667%; -} -.col-xs-10 { - width: 83.33333333%; -} -.col-xs-9 { - width: 75%; -} -.col-xs-8 { - width: 66.66666667%; -} -.col-xs-7 { - width: 58.33333333%; -} -.col-xs-6 { - width: 50%; -} -.col-xs-5 { - width: 41.66666667%; -} -.col-xs-4 { - width: 33.33333333%; -} -.col-xs-3 { - width: 25%; -} -.col-xs-2 { - width: 16.66666667%; -} -.col-xs-1 { - width: 8.33333333%; -} -.col-xs-pull-12 { - right: 100%; -} -.col-xs-pull-11 { - right: 91.66666667%; -} -.col-xs-pull-10 { - right: 83.33333333%; -} -.col-xs-pull-9 { - right: 75%; -} -.col-xs-pull-8 { - right: 66.66666667%; -} -.col-xs-pull-7 { - right: 58.33333333%; -} -.col-xs-pull-6 { - right: 50%; -} -.col-xs-pull-5 { - right: 41.66666667%; -} -.col-xs-pull-4 { - right: 33.33333333%; -} -.col-xs-pull-3 { - right: 25%; -} -.col-xs-pull-2 { - right: 16.66666667%; -} -.col-xs-pull-1 { - right: 8.33333333%; -} -.col-xs-pull-0 { - right: auto; -} -.col-xs-push-12 { - left: 100%; -} -.col-xs-push-11 { - left: 91.66666667%; -} -.col-xs-push-10 { - left: 83.33333333%; -} -.col-xs-push-9 { - left: 75%; -} -.col-xs-push-8 { - left: 66.66666667%; -} -.col-xs-push-7 { - left: 58.33333333%; -} -.col-xs-push-6 { - left: 50%; -} -.col-xs-push-5 { - left: 41.66666667%; -} -.col-xs-push-4 { - left: 33.33333333%; -} -.col-xs-push-3 { - left: 25%; -} -.col-xs-push-2 { - left: 16.66666667%; -} -.col-xs-push-1 { - left: 8.33333333%; -} -.col-xs-push-0 { - left: auto; -} -.col-xs-offset-12 { - margin-left: 100%; -} -.col-xs-offset-11 { - margin-left: 91.66666667%; -} -.col-xs-offset-10 { - margin-left: 83.33333333%; -} -.col-xs-offset-9 { - margin-left: 75%; -} -.col-xs-offset-8 { - margin-left: 66.66666667%; -} -.col-xs-offset-7 { - margin-left: 58.33333333%; -} -.col-xs-offset-6 { - margin-left: 50%; -} -.col-xs-offset-5 { - margin-left: 41.66666667%; -} -.col-xs-offset-4 { - margin-left: 33.33333333%; -} -.col-xs-offset-3 { - margin-left: 25%; -} -.col-xs-offset-2 { - margin-left: 16.66666667%; -} -.col-xs-offset-1 { - margin-left: 8.33333333%; -} -.col-xs-offset-0 { - margin-left: 0; -} -@media (min-width: 768px) { - .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666667%; - } - .col-sm-10 { - width: 83.33333333%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666667%; - } - .col-sm-7 { - width: 58.33333333%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666667%; - } - .col-sm-4 { - width: 33.33333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.66666667%; - } - .col-sm-1 { - width: 8.33333333%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666667%; - } - .col-sm-pull-10 { - right: 83.33333333%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666667%; - } - .col-sm-pull-7 { - right: 58.33333333%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666667%; - } - .col-sm-pull-4 { - right: 33.33333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.66666667%; - } - .col-sm-pull-1 { - right: 8.33333333%; - } - .col-sm-pull-0 { - right: auto; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666667%; - } - .col-sm-push-10 { - left: 83.33333333%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666667%; - } - .col-sm-push-7 { - left: 58.33333333%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666667%; - } - .col-sm-push-4 { - left: 33.33333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.66666667%; - } - .col-sm-push-1 { - left: 8.33333333%; - } - .col-sm-push-0 { - left: auto; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666667%; - } - .col-sm-offset-10 { - margin-left: 83.33333333%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666667%; - } - .col-sm-offset-7 { - margin-left: 58.33333333%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.66666667%; - } - .col-sm-offset-1 { - margin-left: 8.33333333%; - } - .col-sm-offset-0 { - margin-left: 0; - } -} -@media (min-width: 992px) { - .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666667%; - } - .col-md-10 { - width: 83.33333333%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666667%; - } - .col-md-7 { - width: 58.33333333%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666667%; - } - .col-md-4 { - width: 33.33333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.66666667%; - } - .col-md-1 { - width: 8.33333333%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666667%; - } - .col-md-pull-10 { - right: 83.33333333%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666667%; - } - .col-md-pull-7 { - right: 58.33333333%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666667%; - } - .col-md-pull-4 { - right: 33.33333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.66666667%; - } - .col-md-pull-1 { - right: 8.33333333%; - } - .col-md-pull-0 { - right: auto; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666667%; - } - .col-md-push-10 { - left: 83.33333333%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666667%; - } - .col-md-push-7 { - left: 58.33333333%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666667%; - } - .col-md-push-4 { - left: 33.33333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.66666667%; - } - .col-md-push-1 { - left: 8.33333333%; - } - .col-md-push-0 { - left: auto; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666667%; - } - .col-md-offset-10 { - margin-left: 83.33333333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666667%; - } - .col-md-offset-7 { - margin-left: 58.33333333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.66666667%; - } - .col-md-offset-1 { - margin-left: 8.33333333%; - } - .col-md-offset-0 { - margin-left: 0; - } -} -@media (min-width: 1200px) { - .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666667%; - } - .col-lg-10 { - width: 83.33333333%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666667%; - } - .col-lg-7 { - width: 58.33333333%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666667%; - } - .col-lg-4 { - width: 33.33333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.66666667%; - } - .col-lg-1 { - width: 8.33333333%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666667%; - } - .col-lg-pull-10 { - right: 83.33333333%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666667%; - } - .col-lg-pull-7 { - right: 58.33333333%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666667%; - } - .col-lg-pull-4 { - right: 33.33333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.66666667%; - } - .col-lg-pull-1 { - right: 8.33333333%; - } - .col-lg-pull-0 { - right: auto; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666667%; - } - .col-lg-push-10 { - left: 83.33333333%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666667%; - } - .col-lg-push-7 { - left: 58.33333333%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666667%; - } - .col-lg-push-4 { - left: 33.33333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.66666667%; - } - .col-lg-push-1 { - left: 8.33333333%; - } - .col-lg-push-0 { - left: auto; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666667%; - } - .col-lg-offset-10 { - margin-left: 83.33333333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666667%; - } - .col-lg-offset-7 { - margin-left: 58.33333333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66666667%; - } - .col-lg-offset-1 { - margin-left: 8.33333333%; - } - .col-lg-offset-0 { - margin-left: 0; - } -} -table { - background-color: transparent; -} -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #777; - text-align: left; -} -th { - text-align: left; -} -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px; -} -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #ddd; -} -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #ddd; -} -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} -.table > tbody + tbody { - border-top: 2px solid #ddd; -} -.table .table { - background-color: #fff; -} -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 5px; -} -.table-bordered { - border: 1px solid #ddd; -} -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #ddd; -} -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} -.table-striped > tbody > tr:nth-of-type(odd) { - background-color: #f9f9f9; -} -.table-hover > tbody > tr:hover { - background-color: #f5f5f5; -} -table col[class*="col-"] { - position: static; - display: table-column; - float: none; -} -table td[class*="col-"], -table th[class*="col-"] { - position: static; - display: table-cell; - float: none; -} -.table > thead > tr > td.active, -.table > tbody > tr > td.active, -.table > tfoot > tr > td.active, -.table > thead > tr > th.active, -.table > tbody > tr > th.active, -.table > tfoot > tr > th.active, -.table > thead > tr.active > td, -.table > tbody > tr.active > td, -.table > tfoot > tr.active > td, -.table > thead > tr.active > th, -.table > tbody > tr.active > th, -.table > tfoot > tr.active > th { - background-color: #f5f5f5; -} -.table-hover > tbody > tr > td.active:hover, -.table-hover > tbody > tr > th.active:hover, -.table-hover > tbody > tr.active:hover > td, -.table-hover > tbody > tr:hover > .active, -.table-hover > tbody > tr.active:hover > th { - background-color: #e8e8e8; -} -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: #dff0d8; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr:hover > .success, -.table-hover > tbody > tr.success:hover > th { - background-color: #d0e9c6; -} -.table > thead > tr > td.info, -.table > tbody > tr > td.info, -.table > tfoot > tr > td.info, -.table > thead > tr > th.info, -.table > tbody > tr > th.info, -.table > tfoot > tr > th.info, -.table > thead > tr.info > td, -.table > tbody > tr.info > td, -.table > tfoot > tr.info > td, -.table > thead > tr.info > th, -.table > tbody > tr.info > th, -.table > tfoot > tr.info > th { - background-color: #d9edf7; -} -.table-hover > tbody > tr > td.info:hover, -.table-hover > tbody > tr > th.info:hover, -.table-hover > tbody > tr.info:hover > td, -.table-hover > tbody > tr:hover > .info, -.table-hover > tbody > tr.info:hover > th { - background-color: #c4e3f3; -} -.table > thead > tr > td.warning, -.table > tbody > tr > td.warning, -.table > tfoot > tr > td.warning, -.table > thead > tr > th.warning, -.table > tbody > tr > th.warning, -.table > tfoot > tr > th.warning, -.table > thead > tr.warning > td, -.table > tbody > tr.warning > td, -.table > tfoot > tr.warning > td, -.table > thead > tr.warning > th, -.table > tbody > tr.warning > th, -.table > tfoot > tr.warning > th { - background-color: #fcf8e3; -} -.table-hover > tbody > tr > td.warning:hover, -.table-hover > tbody > tr > th.warning:hover, -.table-hover > tbody > tr.warning:hover > td, -.table-hover > tbody > tr:hover > .warning, -.table-hover > tbody > tr.warning:hover > th { - background-color: #faf2cc; -} -.table > thead > tr > td.danger, -.table > tbody > tr > td.danger, -.table > tfoot > tr > td.danger, -.table > thead > tr > th.danger, -.table > tbody > tr > th.danger, -.table > tfoot > tr > th.danger, -.table > thead > tr.danger > td, -.table > tbody > tr.danger > td, -.table > tfoot > tr.danger > td, -.table > thead > tr.danger > th, -.table > tbody > tr.danger > th, -.table > tfoot > tr.danger > th { - background-color: #f2dede; -} -.table-hover > tbody > tr > td.danger:hover, -.table-hover > tbody > tr > th.danger:hover, -.table-hover > tbody > tr.danger:hover > td, -.table-hover > tbody > tr:hover > .danger, -.table-hover > tbody > tr.danger:hover > th { - background-color: #ebcccc; -} -.table-responsive { - min-height: .01%; - overflow-x: auto; -} -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #ddd; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0; -} -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333; - border: 0; - border-bottom: 1px solid #e5e5e5; -} -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: bold; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal; -} -input[type="file"] { - display: block; -} -input[type="range"] { - display: block; - width: 100%; -} -select[multiple], -select[size] { - height: auto; -} -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -output { - display: block; - padding-top: 7px; - font-size: 14px; - line-height: 1.42857143; - color: #555; -} -.form-control { - display: block; - width: 100%; - height: 34px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - color: #555; - background-color: #fff; - background-image: none; - border: 1px solid #ccc; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; -} -.form-control:focus { - border-color: #66afe9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); -} -.form-control::-moz-placeholder { - color: #999; - opacity: 1; -} -.form-control:-ms-input-placeholder { - color: #999; -} -.form-control::-webkit-input-placeholder { - color: #999; -} -.form-control::-ms-expand { - background-color: transparent; - border: 0; -} -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - background-color: #eee; - opacity: 1; -} -.form-control[disabled], -fieldset[disabled] .form-control { - cursor: not-allowed; -} -textarea.form-control { - height: auto; -} -input[type="search"] { - -webkit-appearance: none; -} -@media screen and (-webkit-min-device-pixel-ratio: 0) { - input[type="date"].form-control, - input[type="time"].form-control, - input[type="datetime-local"].form-control, - input[type="month"].form-control { - line-height: 34px; - } - input[type="date"].input-sm, - input[type="time"].input-sm, - input[type="datetime-local"].input-sm, - input[type="month"].input-sm, - .input-group-sm input[type="date"], - .input-group-sm input[type="time"], - .input-group-sm input[type="datetime-local"], - .input-group-sm input[type="month"] { - line-height: 30px; - } - input[type="date"].input-lg, - input[type="time"].input-lg, - input[type="datetime-local"].input-lg, - input[type="month"].input-lg, - .input-group-lg input[type="date"], - .input-group-lg input[type="time"], - .input-group-lg input[type="datetime-local"], - .input-group-lg input[type="month"] { - line-height: 46px; - } -} -.form-group { - margin-bottom: 15px; -} -.radio, -.checkbox { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px; -} -.radio label, -.checkbox label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - cursor: pointer; -} -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { - position: absolute; - margin-top: 4px \9; - margin-left: -20px; -} -.radio + .radio, -.checkbox + .checkbox { - margin-top: -5px; -} -.radio-inline, -.checkbox-inline { - position: relative; - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - vertical-align: middle; - cursor: pointer; -} -.radio-inline + .radio-inline, -.checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 10px; -} -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"].disabled, -input[type="checkbox"].disabled, -fieldset[disabled] input[type="radio"], -fieldset[disabled] input[type="checkbox"] { - cursor: not-allowed; -} -.radio-inline.disabled, -.checkbox-inline.disabled, -fieldset[disabled] .radio-inline, -fieldset[disabled] .checkbox-inline { - cursor: not-allowed; -} -.radio.disabled label, -.checkbox.disabled label, -fieldset[disabled] .radio label, -fieldset[disabled] .checkbox label { - cursor: not-allowed; -} -.form-control-static { - min-height: 34px; - padding-top: 7px; - padding-bottom: 7px; - margin-bottom: 0; -} -.form-control-static.input-lg, -.form-control-static.input-sm { - padding-right: 0; - padding-left: 0; -} -.input-sm { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-sm { - height: 30px; - line-height: 30px; -} -textarea.input-sm, -select[multiple].input-sm { - height: auto; -} -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.form-group-sm select.form-control { - height: 30px; - line-height: 30px; -} -.form-group-sm textarea.form-control, -.form-group-sm select[multiple].form-control { - height: auto; -} -.form-group-sm .form-control-static { - height: 30px; - min-height: 32px; - padding: 6px 10px; - font-size: 12px; - line-height: 1.5; -} -.input-lg { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -select.input-lg { - height: 46px; - line-height: 46px; -} -textarea.input-lg, -select[multiple].input-lg { - height: auto; -} -.form-group-lg .form-control { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -.form-group-lg select.form-control { - height: 46px; - line-height: 46px; -} -.form-group-lg textarea.form-control, -.form-group-lg select[multiple].form-control { - height: auto; -} -.form-group-lg .form-control-static { - height: 46px; - min-height: 38px; - padding: 11px 16px; - font-size: 18px; - line-height: 1.3333333; -} -.has-feedback { - position: relative; -} -.has-feedback .form-control { - padding-right: 42.5px; -} -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 34px; - height: 34px; - line-height: 34px; - text-align: center; - pointer-events: none; -} -.input-lg + .form-control-feedback, -.input-group-lg + .form-control-feedback, -.form-group-lg .form-control + .form-control-feedback { - width: 46px; - height: 46px; - line-height: 46px; -} -.input-sm + .form-control-feedback, -.input-group-sm + .form-control-feedback, -.form-group-sm .form-control + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px; -} -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline, -.has-success.radio label, -.has-success.checkbox label, -.has-success.radio-inline label, -.has-success.checkbox-inline label { - color: #3c763d; -} -.has-success .form-control { - border-color: #3c763d; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-success .form-control:focus { - border-color: #2b542c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; -} -.has-success .input-group-addon { - color: #3c763d; - background-color: #dff0d8; - border-color: #3c763d; -} -.has-success .form-control-feedback { - color: #3c763d; -} -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline, -.has-warning.radio label, -.has-warning.checkbox label, -.has-warning.radio-inline label, -.has-warning.checkbox-inline label { - color: #8a6d3b; -} -.has-warning .form-control { - border-color: #8a6d3b; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-warning .form-control:focus { - border-color: #66512c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; -} -.has-warning .input-group-addon { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #8a6d3b; -} -.has-warning .form-control-feedback { - color: #8a6d3b; -} -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline, -.has-error.radio label, -.has-error.checkbox label, -.has-error.radio-inline label, -.has-error.checkbox-inline label { - color: #a94442; -} -.has-error .form-control { - border-color: #a94442; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-error .form-control:focus { - border-color: #843534; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; -} -.has-error .input-group-addon { - color: #a94442; - background-color: #f2dede; - border-color: #a94442; -} -.has-error .form-control-feedback { - color: #a94442; -} -.has-feedback label ~ .form-control-feedback { - top: 25px; -} -.has-feedback label.sr-only ~ .form-control-feedback { - top: 0; -} -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #737373; -} -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .form-inline .form-control-static { - display: inline-block; - } - .form-inline .input-group { - display: inline-table; - vertical-align: middle; - } - .form-inline .input-group .input-group-addon, - .form-inline .input-group .input-group-btn, - .form-inline .input-group .form-control { - width: auto; - } - .form-inline .input-group > .form-control { - width: 100%; - } - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio, - .form-inline .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio label, - .form-inline .checkbox label { - padding-left: 0; - } - .form-inline .radio input[type="radio"], - .form-inline .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .form-inline .has-feedback .form-control-feedback { - top: 0; - } -} -.form-horizontal .radio, -.form-horizontal .checkbox, -.form-horizontal .radio-inline, -.form-horizontal .checkbox-inline { - padding-top: 7px; - margin-top: 0; - margin-bottom: 0; -} -.form-horizontal .radio, -.form-horizontal .checkbox { - min-height: 27px; -} -.form-horizontal .form-group { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 768px) { - .form-horizontal .control-label { - padding-top: 7px; - margin-bottom: 0; - text-align: right; - } -} -.form-horizontal .has-feedback .form-control-feedback { - right: 15px; -} -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 11px; - font-size: 18px; - } -} -@media (min-width: 768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - font-size: 12px; - } -} -.btn { - display: inline-block; - padding: 6px 12px; - margin-bottom: 0; - font-size: 14px; - font-weight: normal; - line-height: 1.42857143; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #333; - text-decoration: none; -} -.btn:active, -.btn.active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - cursor: not-allowed; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; - opacity: .65; -} -a.btn.disabled, -fieldset[disabled] a.btn { - pointer-events: none; -} -.btn-default { - color: #333; - background-color: #fff; - border-color: #ccc; -} -.btn-default:focus, -.btn-default.focus { - color: #333; - background-color: #e6e6e6; - border-color: #8c8c8c; -} -.btn-default:hover { - color: #333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active:hover, -.btn-default.active:hover, -.open > .dropdown-toggle.btn-default:hover, -.btn-default:active:focus, -.btn-default.active:focus, -.open > .dropdown-toggle.btn-default:focus, -.btn-default:active.focus, -.btn-default.active.focus, -.open > .dropdown-toggle.btn-default.focus { - color: #333; - background-color: #d4d4d4; - border-color: #8c8c8c; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus { - background-color: #fff; - border-color: #ccc; -} -.btn-default .badge { - color: #fff; - background-color: #333; -} -.btn-primary { - color: #fff; - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary:focus, -.btn-primary.focus { - color: #fff; - background-color: #286090; - border-color: #122b40; -} -.btn-primary:hover { - color: #fff; - background-color: #286090; - border-color: #204d74; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #fff; - background-color: #286090; - border-color: #204d74; -} -.btn-primary:active:hover, -.btn-primary.active:hover, -.open > .dropdown-toggle.btn-primary:hover, -.btn-primary:active:focus, -.btn-primary.active:focus, -.open > .dropdown-toggle.btn-primary:focus, -.btn-primary:active.focus, -.btn-primary.active.focus, -.open > .dropdown-toggle.btn-primary.focus { - color: #fff; - background-color: #204d74; - border-color: #122b40; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus { - background-color: #337ab7; - border-color: #2e6da4; -} -.btn-primary .badge { - color: #337ab7; - background-color: #fff; -} -.btn-success { - color: #fff; - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success:focus, -.btn-success.focus { - color: #fff; - background-color: #449d44; - border-color: #255625; -} -.btn-success:hover { - color: #fff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #fff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active:hover, -.btn-success.active:hover, -.open > .dropdown-toggle.btn-success:hover, -.btn-success:active:focus, -.btn-success.active:focus, -.open > .dropdown-toggle.btn-success:focus, -.btn-success:active.focus, -.btn-success.active.focus, -.open > .dropdown-toggle.btn-success.focus { - color: #fff; - background-color: #398439; - border-color: #255625; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus { - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success .badge { - color: #5cb85c; - background-color: #fff; -} -.btn-info { - color: #fff; - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info:focus, -.btn-info.focus { - color: #fff; - background-color: #31b0d5; - border-color: #1b6d85; -} -.btn-info:hover { - color: #fff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #fff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active:hover, -.btn-info.active:hover, -.open > .dropdown-toggle.btn-info:hover, -.btn-info:active:focus, -.btn-info.active:focus, -.open > .dropdown-toggle.btn-info:focus, -.btn-info:active.focus, -.btn-info.active.focus, -.open > .dropdown-toggle.btn-info.focus { - color: #fff; - background-color: #269abc; - border-color: #1b6d85; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus { - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info .badge { - color: #5bc0de; - background-color: #fff; -} -.btn-warning { - color: #fff; - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning:focus, -.btn-warning.focus { - color: #fff; - background-color: #ec971f; - border-color: #985f0d; -} -.btn-warning:hover { - color: #fff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #fff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active:hover, -.btn-warning.active:hover, -.open > .dropdown-toggle.btn-warning:hover, -.btn-warning:active:focus, -.btn-warning.active:focus, -.open > .dropdown-toggle.btn-warning:focus, -.btn-warning:active.focus, -.btn-warning.active.focus, -.open > .dropdown-toggle.btn-warning.focus { - color: #fff; - background-color: #d58512; - border-color: #985f0d; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus { - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning .badge { - color: #f0ad4e; - background-color: #fff; -} -.btn-danger { - color: #fff; - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger:focus, -.btn-danger.focus { - color: #fff; - background-color: #c9302c; - border-color: #761c19; -} -.btn-danger:hover { - color: #fff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #fff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active:hover, -.btn-danger.active:hover, -.open > .dropdown-toggle.btn-danger:hover, -.btn-danger:active:focus, -.btn-danger.active:focus, -.open > .dropdown-toggle.btn-danger:focus, -.btn-danger:active.focus, -.btn-danger.active.focus, -.open > .dropdown-toggle.btn-danger.focus { - color: #fff; - background-color: #ac2925; - border-color: #761c19; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus { - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger .badge { - color: #d9534f; - background-color: #fff; -} -.btn-link { - font-weight: normal; - color: #337ab7; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #23527c; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #777; - text-decoration: none; -} -.btn-lg, -.btn-group-lg > .btn { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -.btn-sm, -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-xs, -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} -.fade { - opacity: 0; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear; -} -.fade.in { - opacity: 1; -} -.collapse { - display: none; -} -.collapse.in { - display: block; -} -tr.collapse.in { - display: table-row; -} -tbody.collapse.in { - display: table-row-group; -} -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; - -webkit-transition-duration: .35s; - -o-transition-duration: .35s; - transition-duration: .35s; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility; -} -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px dashed; - border-top: 4px solid \9; - border-right: 4px solid transparent; - border-left: 4px solid transparent; -} -.dropup, -.dropdown { - position: relative; -} -.dropdown-toggle:focus { - outline: 0; -} -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - text-align: left; - list-style: none; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .15); - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); - box-shadow: 0 6px 12px rgba(0, 0, 0, .175); -} -.dropdown-menu.pull-right { - right: 0; - left: auto; -} -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 1.42857143; - color: #333; - white-space: nowrap; -} -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - color: #262626; - text-decoration: none; - background-color: #f5f5f5; -} -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: #fff; - text-decoration: none; - background-color: #337ab7; - outline: 0; -} -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: #777; -} -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - cursor: not-allowed; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} -.open > .dropdown-menu { - display: block; -} -.open > a { - outline: 0; -} -.dropdown-menu-right { - right: 0; - left: auto; -} -.dropdown-menu-left { - right: auto; - left: 0; -} -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #777; - white-space: nowrap; -} -.dropdown-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 990; -} -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - content: ""; - border-top: 0; - border-bottom: 4px dashed; - border-bottom: 4px solid \9; -} -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 2px; -} -@media (min-width: 768px) { - .navbar-right .dropdown-menu { - right: 0; - left: auto; - } - .navbar-right .dropdown-menu-left { - right: auto; - left: 0; - } -} -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle; -} -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - float: left; -} -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover, -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus, -.btn-group > .btn:active, -.btn-group-vertical > .btn:active, -.btn-group > .btn.active, -.btn-group-vertical > .btn.active { - z-index: 2; -} -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group { - margin-left: -1px; -} -.btn-toolbar { - margin-left: -5px; -} -.btn-toolbar .btn, -.btn-toolbar .btn-group, -.btn-toolbar .input-group { - float: left; -} -.btn-toolbar > .btn, -.btn-toolbar > .btn-group, -.btn-toolbar > .input-group { - margin-left: 5px; -} -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0; -} -.btn-group > .btn:first-child { - margin-left: 0; -} -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.btn-group > .btn:last-child:not(:first-child), -.btn-group > .dropdown-toggle:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group > .btn-group { - float: left; -} -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} -.btn-group > .btn + .dropdown-toggle { - padding-right: 8px; - padding-left: 8px; -} -.btn-group > .btn-lg + .dropdown-toggle { - padding-right: 12px; - padding-left: 12px; -} -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -} -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none; -} -.btn .caret { - margin-left: 0; -} -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0; -} -.dropup .btn-lg .caret { - border-width: 0 5px 5px; -} -.btn-group-vertical > .btn, -.btn-group-vertical > .btn-group, -.btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100%; -} -.btn-group-vertical > .btn-group > .btn { - float: none; -} -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0; -} -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; -} -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate; -} -.btn-group-justified > .btn, -.btn-group-justified > .btn-group { - display: table-cell; - float: none; - width: 1%; -} -.btn-group-justified > .btn-group .btn { - width: 100%; -} -.btn-group-justified > .btn-group .dropdown-menu { - left: auto; -} -[data-toggle="buttons"] > .btn input[type="radio"], -[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], -[data-toggle="buttons"] > .btn input[type="checkbox"], -[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none; -} -.input-group { - position: relative; - display: table; - border-collapse: separate; -} -.input-group[class*="col-"] { - float: none; - padding-right: 0; - padding-left: 0; -} -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0; -} -.input-group .form-control:focus { - z-index: 3; -} -.input-group-lg > .form-control, -.input-group-lg > .input-group-addon, -.input-group-lg > .input-group-btn > .btn { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; - border-radius: 6px; -} -select.input-group-lg > .form-control, -select.input-group-lg > .input-group-addon, -select.input-group-lg > .input-group-btn > .btn { - height: 46px; - line-height: 46px; -} -textarea.input-group-lg > .form-control, -textarea.input-group-lg > .input-group-addon, -textarea.input-group-lg > .input-group-btn > .btn, -select[multiple].input-group-lg > .form-control, -select[multiple].input-group-lg > .input-group-addon, -select[multiple].input-group-lg > .input-group-btn > .btn { - height: auto; -} -.input-group-sm > .form-control, -.input-group-sm > .input-group-addon, -.input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-group-sm > .form-control, -select.input-group-sm > .input-group-addon, -select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px; -} -textarea.input-group-sm > .form-control, -textarea.input-group-sm > .input-group-addon, -textarea.input-group-sm > .input-group-btn > .btn, -select[multiple].input-group-sm > .form-control, -select[multiple].input-group-sm > .input-group-addon, -select[multiple].input-group-sm > .input-group-btn > .btn { - height: auto; -} -.input-group-addon, -.input-group-btn, -.input-group .form-control { - display: table-cell; -} -.input-group-addon:not(:first-child):not(:last-child), -.input-group-btn:not(:first-child):not(:last-child), -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} -.input-group-addon, -.input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle; -} -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: normal; - line-height: 1; - color: #555; - text-align: center; - background-color: #eee; - border: 1px solid #ccc; - border-radius: 4px; -} -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px; -} -.input-group-addon.input-lg { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px; -} -.input-group-addon input[type="radio"], -.input-group-addon input[type="checkbox"] { - margin-top: 0; -} -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group > .btn, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), -.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.input-group-addon:first-child { - border-right: 0; -} -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group > .btn, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child), -.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.input-group-addon:last-child { - border-left: 0; -} -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap; -} -.input-group-btn > .btn { - position: relative; -} -.input-group-btn > .btn + .btn { - margin-left: -1px; -} -.input-group-btn > .btn:hover, -.input-group-btn > .btn:focus, -.input-group-btn > .btn:active { - z-index: 2; -} -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group { - margin-right: -1px; -} -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group { - z-index: 2; - margin-left: -1px; -} -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none; -} -.nav > li { - position: relative; - display: block; -} -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px; -} -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #eee; -} -.nav > li.disabled > a { - color: #777; -} -.nav > li.disabled > a:hover, -.nav > li.disabled > a:focus { - color: #777; - text-decoration: none; - cursor: not-allowed; - background-color: transparent; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - background-color: #eee; - border-color: #337ab7; -} -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.nav > li > a > img { - max-width: none; -} -.nav-tabs { - border-bottom: 1px solid #ddd; -} -.nav-tabs > li { - float: left; - margin-bottom: -1px; -} -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 4px 4px 0 0; -} -.nav-tabs > li > a:hover { - border-color: #eee #eee #ddd; -} -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - color: #555; - cursor: default; - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: transparent; -} -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0; -} -.nav-tabs.nav-justified > li { - float: none; -} -.nav-tabs.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-tabs.nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs.nav-justified > .active > a, -.nav-tabs.nav-justified > .active > a:hover, -.nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #ddd; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs.nav-justified > .active > a, - .nav-tabs.nav-justified > .active > a:hover, - .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #fff; - } -} -.nav-pills > li { - float: left; -} -.nav-pills > li > a { - border-radius: 4px; -} -.nav-pills > li + li { - margin-left: 2px; -} -.nav-pills > li.active > a, -.nav-pills > li.active > a:hover, -.nav-pills > li.active > a:focus { - color: #fff; - background-color: #337ab7; -} -.nav-stacked > li { - float: none; -} -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0; -} -.nav-justified { - width: 100%; -} -.nav-justified > li { - float: none; -} -.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs-justified { - border-bottom: 0; -} -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs-justified > .active > a, -.nav-tabs-justified > .active > a:hover, -.nav-tabs-justified > .active > a:focus { - border: 1px solid #ddd; -} -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs-justified > .active > a, - .nav-tabs-justified > .active > a:hover, - .nav-tabs-justified > .active > a:focus { - border-bottom-color: #fff; - } -} -.tab-content > .tab-pane { - display: none; -} -.tab-content > .active { - display: block; -} -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.navbar { - position: relative; - min-height: 50px; - margin-bottom: 20px; - border: 1px solid transparent; -} -@media (min-width: 768px) { - .navbar { - border-radius: 4px; - } -} -@media (min-width: 768px) { - .navbar-header { - float: left; - } -} -.navbar-collapse { - padding-right: 15px; - padding-left: 15px; - overflow-x: visible; - -webkit-overflow-scrolling: touch; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); -} -.navbar-collapse.in { - overflow-y: auto; -} -@media (min-width: 768px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important; - } - .navbar-collapse.in { - overflow-y: visible; - } - .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - padding-right: 0; - padding-left: 0; - } -} -.navbar-fixed-top .navbar-collapse, -.navbar-fixed-bottom .navbar-collapse { - max-height: 340px; -} -@media (max-device-width: 480px) and (orientation: landscape) { - .navbar-fixed-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - max-height: 200px; - } -} -.container > .navbar-header, -.container-fluid > .navbar-header, -.container > .navbar-collapse, -.container-fluid > .navbar-collapse { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 768px) { - .container > .navbar-header, - .container-fluid > .navbar-header, - .container > .navbar-collapse, - .container-fluid > .navbar-collapse { - margin-right: 0; - margin-left: 0; - } -} -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px; -} -@media (min-width: 768px) { - .navbar-static-top { - border-radius: 0; - } -} -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} -@media (min-width: 768px) { - .navbar-fixed-top, - .navbar-fixed-bottom { - border-radius: 0; - } -} -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px; -} -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0; -} -.navbar-brand { - float: left; - height: 50px; - padding: 15px 15px; - font-size: 18px; - line-height: 20px; -} -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none; -} -.navbar-brand > img { - display: block; -} -@media (min-width: 768px) { - .navbar > .container .navbar-brand, - .navbar > .container-fluid .navbar-brand { - margin-left: -15px; - } -} -.navbar-toggle { - position: relative; - float: right; - padding: 9px 10px; - margin-top: 8px; - margin-right: 15px; - margin-bottom: 8px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} -.navbar-toggle:focus { - outline: 0; -} -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px; -} -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px; -} -@media (min-width: 768px) { - .navbar-toggle { - display: none; - } -} -.navbar-nav { - margin: 7.5px -15px; -} -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px; -} -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-nav .open .dropdown-menu > li > a, - .navbar-nav .open .dropdown-menu .dropdown-header { - padding: 5px 15px 5px 25px; - } - .navbar-nav .open .dropdown-menu > li > a { - line-height: 20px; - } - .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-nav .open .dropdown-menu > li > a:focus { - background-image: none; - } -} -@media (min-width: 768px) { - .navbar-nav { - float: left; - margin: 0; - } - .navbar-nav > li { - float: left; - } - .navbar-nav > li > a { - padding-top: 15px; - padding-bottom: 15px; - } -} -.navbar-form { - padding: 10px 15px; - margin-top: 8px; - margin-right: -15px; - margin-bottom: 8px; - margin-left: -15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); -} -@media (min-width: 768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .navbar-form .form-control-static { - display: inline-block; - } - .navbar-form .input-group { - display: inline-table; - vertical-align: middle; - } - .navbar-form .input-group .input-group-addon, - .navbar-form .input-group .input-group-btn, - .navbar-form .input-group .form-control { - width: auto; - } - .navbar-form .input-group > .form-control { - width: 100%; - } - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio, - .navbar-form .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio label, - .navbar-form .checkbox label { - padding-left: 0; - } - .navbar-form .radio input[type="radio"], - .navbar-form .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .navbar-form .has-feedback .form-control-feedback { - top: 0; - } -} -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px; - } - .navbar-form .form-group:last-child { - margin-bottom: 0; - } -} -@media (min-width: 768px) { - .navbar-form { - width: auto; - padding-top: 0; - padding-bottom: 0; - margin-right: 0; - margin-left: 0; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } -} -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - margin-bottom: 0; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.navbar-btn { - margin-top: 8px; - margin-bottom: 8px; -} -.navbar-btn.btn-sm { - margin-top: 10px; - margin-bottom: 10px; -} -.navbar-btn.btn-xs { - margin-top: 14px; - margin-bottom: 14px; -} -.navbar-text { - margin-top: 15px; - margin-bottom: 15px; -} -@media (min-width: 768px) { - .navbar-text { - float: left; - margin-right: 15px; - margin-left: 15px; - } -} -@media (min-width: 768px) { - .navbar-left { - float: left !important; - } - .navbar-right { - float: right !important; - margin-right: -15px; - } - .navbar-right ~ .navbar-right { - margin-right: 0; - } -} -.navbar-default { - background-color: #f8f8f8; - border-color: #e7e7e7; -} -.navbar-default .navbar-brand { - color: #777; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #5e5e5e; - background-color: transparent; -} -.navbar-default .navbar-text { - color: #777; -} -.navbar-default .navbar-nav > li > a { - color: #777; -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #333; - background-color: transparent; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #555; - background-color: #e7e7e7; -} -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #ccc; - background-color: transparent; -} -.navbar-default .navbar-toggle { - border-color: #ddd; -} -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #ddd; -} -.navbar-default .navbar-toggle .icon-bar { - background-color: #888; -} -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: #e7e7e7; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - color: #555; - background-color: #e7e7e7; -} -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #777; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #333; - background-color: transparent; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #555; - background-color: #e7e7e7; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #ccc; - background-color: transparent; - } -} -.navbar-default .navbar-link { - color: #777; -} -.navbar-default .navbar-link:hover { - color: #333; -} -.navbar-default .btn-link { - color: #777; -} -.navbar-default .btn-link:hover, -.navbar-default .btn-link:focus { - color: #333; -} -.navbar-default .btn-link[disabled]:hover, -fieldset[disabled] .navbar-default .btn-link:hover, -.navbar-default .btn-link[disabled]:focus, -fieldset[disabled] .navbar-default .btn-link:focus { - color: #ccc; -} -.navbar-inverse { - background-color: #222; - border-color: #080808; -} -.navbar-inverse .navbar-brand { - color: #9d9d9d; -} -.navbar-inverse .navbar-brand:hover, -.navbar-inverse .navbar-brand:focus { - color: #fff; - background-color: transparent; -} -.navbar-inverse .navbar-text { - color: #9d9d9d; -} -.navbar-inverse .navbar-nav > li > a { - color: #9d9d9d; -} -.navbar-inverse .navbar-nav > li > a:hover, -.navbar-inverse .navbar-nav > li > a:focus { - color: #fff; - background-color: transparent; -} -.navbar-inverse .navbar-nav > .active > a, -.navbar-inverse .navbar-nav > .active > a:hover, -.navbar-inverse .navbar-nav > .active > a:focus { - color: #fff; - background-color: #080808; -} -.navbar-inverse .navbar-nav > .disabled > a, -.navbar-inverse .navbar-nav > .disabled > a:hover, -.navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444; - background-color: transparent; -} -.navbar-inverse .navbar-toggle { - border-color: #333; -} -.navbar-inverse .navbar-toggle:hover, -.navbar-inverse .navbar-toggle:focus { - background-color: #333; -} -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #fff; -} -.navbar-inverse .navbar-collapse, -.navbar-inverse .navbar-form { - border-color: #101010; -} -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .open > a:hover, -.navbar-inverse .navbar-nav > .open > a:focus { - color: #fff; - background-color: #080808; -} -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #9d9d9d; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #fff; - background-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #fff; - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444; - background-color: transparent; - } -} -.navbar-inverse .navbar-link { - color: #9d9d9d; -} -.navbar-inverse .navbar-link:hover { - color: #fff; -} -.navbar-inverse .btn-link { - color: #9d9d9d; -} -.navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link:focus { - color: #fff; -} -.navbar-inverse .btn-link[disabled]:hover, -fieldset[disabled] .navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link[disabled]:focus, -fieldset[disabled] .navbar-inverse .btn-link:focus { - color: #444; -} -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #f5f5f5; - border-radius: 4px; -} -.breadcrumb > li { - display: inline-block; -} -.breadcrumb > li + li:before { - padding: 0 5px; - color: #ccc; - content: "/\00a0"; -} -.breadcrumb > .active { - color: #777; -} -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px; -} -.pagination > li { - display: inline; -} -.pagination > li > a, -.pagination > li > span { - position: relative; - float: left; - padding: 6px 12px; - margin-left: -1px; - line-height: 1.42857143; - color: #337ab7; - text-decoration: none; - background-color: #fff; - border: 1px solid #ddd; -} -.pagination > li:first-child > a, -.pagination > li:first-child > span { - margin-left: 0; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} -.pagination > li:last-child > a, -.pagination > li:last-child > span { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} -.pagination > li > a:hover, -.pagination > li > span:hover, -.pagination > li > a:focus, -.pagination > li > span:focus { - z-index: 2; - color: #23527c; - background-color: #eee; - border-color: #ddd; -} -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - z-index: 3; - color: #fff; - cursor: default; - background-color: #337ab7; - border-color: #337ab7; -} -.pagination > .disabled > span, -.pagination > .disabled > span:hover, -.pagination > .disabled > span:focus, -.pagination > .disabled > a, -.pagination > .disabled > a:hover, -.pagination > .disabled > a:focus { - color: #777; - cursor: not-allowed; - background-color: #fff; - border-color: #ddd; -} -.pagination-lg > li > a, -.pagination-lg > li > span { - padding: 10px 16px; - font-size: 18px; - line-height: 1.3333333; -} -.pagination-lg > li:first-child > a, -.pagination-lg > li:first-child > span { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; -} -.pagination-lg > li:last-child > a, -.pagination-lg > li:last-child > span { - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; -} -.pagination-sm > li > a, -.pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; -} -.pagination-sm > li:first-child > a, -.pagination-sm > li:first-child > span { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; -} -.pagination-sm > li:last-child > a, -.pagination-sm > li:last-child > span { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} -.pager { - padding-left: 0; - margin: 20px 0; - text-align: center; - list-style: none; -} -.pager li { - display: inline; -} -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 15px; -} -.pager li > a:hover, -.pager li > a:focus { - text-decoration: none; - background-color: #eee; -} -.pager .next > a, -.pager .next > span { - float: right; -} -.pager .previous > a, -.pager .previous > span { - float: left; -} -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #777; - cursor: not-allowed; - background-color: #fff; -} -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} -a.label:hover, -a.label:focus { - color: #fff; - text-decoration: none; - cursor: pointer; -} -.label:empty { - display: none; -} -.btn .label { - position: relative; - top: -1px; -} -.label-default { - background-color: #777; -} -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #5e5e5e; -} -.label-primary { - background-color: #337ab7; -} -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #286090; -} -.label-success { - background-color: #5cb85c; -} -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #449d44; -} -.label-info { - background-color: #5bc0de; -} -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #31b0d5; -} -.label-warning { - background-color: #f0ad4e; -} -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ec971f; -} -.label-danger { - background-color: #d9534f; -} -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: bold; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: middle; - background-color: #777; - border-radius: 10px; -} -.badge:empty { - display: none; -} -.btn .badge { - position: relative; - top: -1px; -} -.btn-xs .badge, -.btn-group-xs > .btn .badge { - top: 0; - padding: 1px 5px; -} -a.badge:hover, -a.badge:focus { - color: #fff; - text-decoration: none; - cursor: pointer; -} -.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #337ab7; - background-color: #fff; -} -.list-group-item > .badge { - float: right; -} -.list-group-item > .badge + .badge { - margin-right: 5px; -} -.nav-pills > li > a > .badge { - margin-left: 3px; -} -.jumbotron { - padding-top: 30px; - padding-bottom: 30px; - margin-bottom: 30px; - color: inherit; - background-color: #eee; -} -.jumbotron h1, -.jumbotron .h1 { - color: inherit; -} -.jumbotron p { - margin-bottom: 15px; - font-size: 21px; - font-weight: 200; -} -.jumbotron > hr { - border-top-color: #d5d5d5; -} -.container .jumbotron, -.container-fluid .jumbotron { - padding-right: 15px; - padding-left: 15px; - border-radius: 6px; -} -.jumbotron .container { - max-width: 100%; -} -@media screen and (min-width: 768px) { - .jumbotron { - padding-top: 48px; - padding-bottom: 48px; - } - .container .jumbotron, - .container-fluid .jumbotron { - padding-right: 60px; - padding-left: 60px; - } - .jumbotron h1, - .jumbotron .h1 { - font-size: 63px; - } -} -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: border .2s ease-in-out; - -o-transition: border .2s ease-in-out; - transition: border .2s ease-in-out; -} -.thumbnail > img, -.thumbnail a > img { - margin-right: auto; - margin-left: auto; -} -a.thumbnail:hover, -a.thumbnail:focus, -a.thumbnail.active { - border-color: #337ab7; -} -.thumbnail .caption { - padding: 9px; - color: #333; -} -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert h4 { - margin-top: 0; - color: inherit; -} -.alert .alert-link { - font-weight: bold; -} -.alert > p, -.alert > ul { - margin-bottom: 0; -} -.alert > p + p { - margin-top: 5px; -} -.alert-dismissable, -.alert-dismissible { - padding-right: 35px; -} -.alert-dismissable .close, -.alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} -.alert-success { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} -.alert-success hr { - border-top-color: #c9e2b3; -} -.alert-success .alert-link { - color: #2b542c; -} -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.alert-info hr { - border-top-color: #a6e1ec; -} -.alert-info .alert-link { - color: #245269; -} -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.alert-warning hr { - border-top-color: #f7e1b5; -} -.alert-warning .alert-link { - color: #66512c; -} -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.alert-danger hr { - border-top-color: #e4b9c0; -} -.alert-danger .alert-link { - color: #843534; -} -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #f5f5f5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); -} -.progress-bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #fff; - text-align: center; - background-color: #337ab7; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - -webkit-transition: width .6s ease; - -o-transition: width .6s ease; - transition: width .6s ease; -} -.progress-striped .progress-bar, -.progress-bar-striped { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px; -} -.progress.active .progress-bar, -.progress-bar.active { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} -.progress-bar-success { - background-color: #5cb85c; -} -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-info { - background-color: #5bc0de; -} -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-warning { - background-color: #f0ad4e; -} -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-danger { - background-color: #d9534f; -} -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.media { - margin-top: 15px; -} -.media:first-child { - margin-top: 0; -} -.media, -.media-body { - overflow: hidden; - zoom: 1; -} -.media-body { - width: 10000px; -} -.media-object { - display: block; -} -.media-object.img-thumbnail { - max-width: none; -} -.media-right, -.media > .pull-right { - padding-left: 10px; -} -.media-left, -.media > .pull-left { - padding-right: 10px; -} -.media-left, -.media-right, -.media-body { - display: table-cell; - vertical-align: top; -} -.media-middle { - vertical-align: middle; -} -.media-bottom { - vertical-align: bottom; -} -.media-heading { - margin-top: 0; - margin-bottom: 5px; -} -.media-list { - padding-left: 0; - list-style: none; -} -.list-group { - padding-left: 0; - margin-bottom: 20px; -} -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #fff; - border: 1px solid #ddd; -} -.list-group-item:first-child { - border-top-left-radius: 4px; - border-top-right-radius: 4px; -} -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; -} -a.list-group-item, -button.list-group-item { - color: #555; -} -a.list-group-item .list-group-item-heading, -button.list-group-item .list-group-item-heading { - color: #333; -} -a.list-group-item:hover, -button.list-group-item:hover, -a.list-group-item:focus, -button.list-group-item:focus { - color: #555; - text-decoration: none; - background-color: #f5f5f5; -} -button.list-group-item { - width: 100%; - text-align: left; -} -.list-group-item.disabled, -.list-group-item.disabled:hover, -.list-group-item.disabled:focus { - color: #777; - cursor: not-allowed; - background-color: #eee; -} -.list-group-item.disabled .list-group-item-heading, -.list-group-item.disabled:hover .list-group-item-heading, -.list-group-item.disabled:focus .list-group-item-heading { - color: inherit; -} -.list-group-item.disabled .list-group-item-text, -.list-group-item.disabled:hover .list-group-item-text, -.list-group-item.disabled:focus .list-group-item-text { - color: #777; -} -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - z-index: 2; - color: #fff; - background-color: #337ab7; - border-color: #337ab7; -} -.list-group-item.active .list-group-item-heading, -.list-group-item.active:hover .list-group-item-heading, -.list-group-item.active:focus .list-group-item-heading, -.list-group-item.active .list-group-item-heading > small, -.list-group-item.active:hover .list-group-item-heading > small, -.list-group-item.active:focus .list-group-item-heading > small, -.list-group-item.active .list-group-item-heading > .small, -.list-group-item.active:hover .list-group-item-heading > .small, -.list-group-item.active:focus .list-group-item-heading > .small { - color: inherit; -} -.list-group-item.active .list-group-item-text, -.list-group-item.active:hover .list-group-item-text, -.list-group-item.active:focus .list-group-item-text { - color: #c7ddef; -} -.list-group-item-success { - color: #3c763d; - background-color: #dff0d8; -} -a.list-group-item-success, -button.list-group-item-success { - color: #3c763d; -} -a.list-group-item-success .list-group-item-heading, -button.list-group-item-success .list-group-item-heading { - color: inherit; -} -a.list-group-item-success:hover, -button.list-group-item-success:hover, -a.list-group-item-success:focus, -button.list-group-item-success:focus { - color: #3c763d; - background-color: #d0e9c6; -} -a.list-group-item-success.active, -button.list-group-item-success.active, -a.list-group-item-success.active:hover, -button.list-group-item-success.active:hover, -a.list-group-item-success.active:focus, -button.list-group-item-success.active:focus { - color: #fff; - background-color: #3c763d; - border-color: #3c763d; -} -.list-group-item-info { - color: #31708f; - background-color: #d9edf7; -} -a.list-group-item-info, -button.list-group-item-info { - color: #31708f; -} -a.list-group-item-info .list-group-item-heading, -button.list-group-item-info .list-group-item-heading { - color: inherit; -} -a.list-group-item-info:hover, -button.list-group-item-info:hover, -a.list-group-item-info:focus, -button.list-group-item-info:focus { - color: #31708f; - background-color: #c4e3f3; -} -a.list-group-item-info.active, -button.list-group-item-info.active, -a.list-group-item-info.active:hover, -button.list-group-item-info.active:hover, -a.list-group-item-info.active:focus, -button.list-group-item-info.active:focus { - color: #fff; - background-color: #31708f; - border-color: #31708f; -} -.list-group-item-warning { - color: #8a6d3b; - background-color: #fcf8e3; -} -a.list-group-item-warning, -button.list-group-item-warning { - color: #8a6d3b; -} -a.list-group-item-warning .list-group-item-heading, -button.list-group-item-warning .list-group-item-heading { - color: inherit; -} -a.list-group-item-warning:hover, -button.list-group-item-warning:hover, -a.list-group-item-warning:focus, -button.list-group-item-warning:focus { - color: #8a6d3b; - background-color: #faf2cc; -} -a.list-group-item-warning.active, -button.list-group-item-warning.active, -a.list-group-item-warning.active:hover, -button.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus, -button.list-group-item-warning.active:focus { - color: #fff; - background-color: #8a6d3b; - border-color: #8a6d3b; -} -.list-group-item-danger { - color: #a94442; - background-color: #f2dede; -} -a.list-group-item-danger, -button.list-group-item-danger { - color: #a94442; -} -a.list-group-item-danger .list-group-item-heading, -button.list-group-item-danger .list-group-item-heading { - color: inherit; -} -a.list-group-item-danger:hover, -button.list-group-item-danger:hover, -a.list-group-item-danger:focus, -button.list-group-item-danger:focus { - color: #a94442; - background-color: #ebcccc; -} -a.list-group-item-danger.active, -button.list-group-item-danger.active, -a.list-group-item-danger.active:hover, -button.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus, -button.list-group-item-danger.active:focus { - color: #fff; - background-color: #a94442; - border-color: #a94442; -} -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px; -} -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3; -} -.panel { - margin-bottom: 20px; - background-color: #fff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: 0 1px 1px rgba(0, 0, 0, .05); -} -.panel-body { - padding: 15px; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} -.panel-title > a, -.panel-title > small, -.panel-title > .small, -.panel-title > small > a, -.panel-title > .small > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .list-group, -.panel > .panel-collapse > .list-group { - margin-bottom: 0; -} -.panel > .list-group .list-group-item, -.panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0; -} -.panel > .list-group:first-child .list-group-item:first-child, -.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} -.list-group + .panel-footer { - border-top-width: 0; -} -.panel > .table, -.panel > .table-responsive > .table, -.panel > .panel-collapse > .table { - margin-bottom: 0; -} -.panel > .table caption, -.panel > .table-responsive > .table caption, -.panel > .panel-collapse > .table caption { - padding-right: 15px; - padding-left: 15px; -} -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px; -} -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive, -.panel > .table + .panel-body, -.panel > .table-responsive + .panel-body { - border-top: 1px solid #ddd; -} -.panel > .table > tbody:first-child > tr:first-child th, -.panel > .table > tbody:first-child > tr:first-child td { - border-top: 0; -} -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} -.panel > .table-bordered > thead > tr:first-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, -.panel > .table-bordered > tbody > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { - border-bottom: 0; -} -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0; -} -.panel > .table-responsive { - margin-bottom: 0; - border: 0; -} -.panel-group { - margin-bottom: 20px; -} -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px; -} -.panel-group .panel + .panel { - margin-top: 5px; -} -.panel-group .panel-heading { - border-bottom: 0; -} -.panel-group .panel-heading + .panel-collapse > .panel-body, -.panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid #ddd; -} -.panel-group .panel-footer { - border-top: 0; -} -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #ddd; -} -.panel-default { - border-color: #ddd; -} -.panel-default > .panel-heading { - color: #333; - background-color: #f5f5f5; - border-color: #ddd; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ddd; -} -.panel-default > .panel-heading .badge { - color: #f5f5f5; - background-color: #333; -} -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ddd; -} -.panel-primary { - border-color: #337ab7; -} -.panel-primary > .panel-heading { - color: #fff; - background-color: #337ab7; - border-color: #337ab7; -} -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #337ab7; -} -.panel-primary > .panel-heading .badge { - color: #337ab7; - background-color: #fff; -} -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #337ab7; -} -.panel-success { - border-color: #d6e9c6; -} -.panel-success > .panel-heading { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #d6e9c6; -} -.panel-success > .panel-heading .badge { - color: #dff0d8; - background-color: #3c763d; -} -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #d6e9c6; -} -.panel-info { - border-color: #bce8f1; -} -.panel-info > .panel-heading { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #bce8f1; -} -.panel-info > .panel-heading .badge { - color: #d9edf7; - background-color: #31708f; -} -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #bce8f1; -} -.panel-warning { - border-color: #faebcc; -} -.panel-warning > .panel-heading { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #faebcc; -} -.panel-warning > .panel-heading .badge { - color: #fcf8e3; - background-color: #8a6d3b; -} -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #faebcc; -} -.panel-danger { - border-color: #ebccd1; -} -.panel-danger > .panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ebccd1; -} -.panel-danger > .panel-heading .badge { - color: #f2dede; - background-color: #a94442; -} -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ebccd1; -} -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden; -} -.embed-responsive .embed-responsive-item, -.embed-responsive iframe, -.embed-responsive embed, -.embed-responsive object, -.embed-responsive video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0; -} -.embed-responsive-16by9 { - padding-bottom: 56.25%; -} -.embed-responsive-4by3 { - padding-bottom: 75%; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, .15); -} -.well-lg { - padding: 24px; - border-radius: 6px; -} -.well-sm { - padding: 9px; - border-radius: 3px; -} -.close { - float: right; - font-size: 21px; - font-weight: bold; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - filter: alpha(opacity=20); - opacity: .2; -} -.close:hover, -.close:focus { - color: #000; - text-decoration: none; - cursor: pointer; - filter: alpha(opacity=50); - opacity: .5; -} -button.close { - -webkit-appearance: none; - padding: 0; - cursor: pointer; - background: transparent; - border: 0; -} -.modal-open { - overflow: hidden; -} -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1050; - display: none; - overflow: hidden; - -webkit-overflow-scrolling: touch; - outline: 0; -} -.modal.fade .modal-dialog { - -webkit-transition: -webkit-transform .3s ease-out; - -o-transition: -o-transform .3s ease-out; - transition: transform .3s ease-out; - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); -} -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -} -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} -.modal-dialog { - position: relative; - width: auto; - margin: 10px; -} -.modal-content { - position: relative; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - outline: 0; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); - box-shadow: 0 3px 9px rgba(0, 0, 0, .5); -} -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000; -} -.modal-backdrop.fade { - filter: alpha(opacity=0); - opacity: 0; -} -.modal-backdrop.in { - filter: alpha(opacity=50); - opacity: .5; -} -.modal-header { - padding: 15px; - border-bottom: 1px solid #e5e5e5; -} -.modal-header .close { - margin-top: -2px; -} -.modal-title { - margin: 0; - line-height: 1.42857143; -} -.modal-body { - position: relative; - padding: 15px; -} -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #e5e5e5; -} -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px; -} -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - } - .modal-sm { - width: 300px; - } -} -@media (min-width: 992px) { - .modal-lg { - width: 900px; - } -} -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 12px; - font-style: normal; - font-weight: normal; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - filter: alpha(opacity=0); - opacity: 0; - - line-break: auto; -} -.tooltip.in { - filter: alpha(opacity=90); - opacity: .9; -} -.tooltip.top { - padding: 5px 0; - margin-top: -3px; -} -.tooltip.right { - padding: 0 5px; - margin-left: 3px; -} -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px; -} -.tooltip.left { - padding: 0 5px; - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #fff; - text-align: center; - background-color: #000; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-left .tooltip-arrow { - right: 5px; - bottom: 0; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-right .tooltip-arrow { - bottom: 0; - left: 5px; - margin-bottom: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-left .tooltip-arrow { - top: 0; - right: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - left: 5px; - margin-top: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - font-style: normal; - font-weight: normal; - line-height: 1.42857143; - text-align: left; - text-align: start; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - word-wrap: normal; - white-space: normal; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - - line-break: auto; -} -.popover.top { - margin-top: -10px; -} -.popover.right { - margin-left: 10px; -} -.popover.bottom { - margin-top: 10px; -} -.popover.left { - margin-left: -10px; -} -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0; -} -.popover-content { - padding: 9px 14px; -} -.popover > .arrow, -.popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover > .arrow { - border-width: 11px; -} -.popover > .arrow:after { - content: ""; - border-width: 10px; -} -.popover.top > .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, .25); - border-bottom-width: 0; -} -.popover.top > .arrow:after { - bottom: 1px; - margin-left: -10px; - content: " "; - border-top-color: #fff; - border-bottom-width: 0; -} -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, .25); - border-left-width: 0; -} -.popover.right > .arrow:after { - bottom: -10px; - left: 1px; - content: " "; - border-right-color: #fff; - border-left-width: 0; -} -.popover.bottom > .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, .25); -} -.popover.bottom > .arrow:after { - top: 1px; - margin-left: -10px; - content: " "; - border-top-width: 0; - border-bottom-color: #fff; -} -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, .25); -} -.popover.left > .arrow:after { - right: 1px; - bottom: -10px; - content: " "; - border-right-width: 0; - border-left-color: #fff; -} -.carousel { - position: relative; -} -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; -} -.carousel-inner > .item { - position: relative; - display: none; - -webkit-transition: .6s ease-in-out left; - -o-transition: .6s ease-in-out left; - transition: .6s ease-in-out left; -} -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - line-height: 1; -} -@media all and (transform-3d), (-webkit-transform-3d) { - .carousel-inner > .item { - -webkit-transition: -webkit-transform .6s ease-in-out; - -o-transition: -o-transform .6s ease-in-out; - transition: transform .6s ease-in-out; - - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000px; - perspective: 1000px; - } - .carousel-inner > .item.next, - .carousel-inner > .item.active.right { - left: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - .carousel-inner > .item.prev, - .carousel-inner > .item.active.left { - left: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - .carousel-inner > .item.next.left, - .carousel-inner > .item.prev.right, - .carousel-inner > .item.active { - left: 0; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} -.carousel-inner > .active { - left: 0; -} -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} -.carousel-inner > .next { - left: 100%; -} -.carousel-inner > .prev { - left: -100%; -} -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} -.carousel-inner > .active.left { - left: -100%; -} -.carousel-inner > .active.right { - left: 100%; -} -.carousel-control { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 15%; - font-size: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); - background-color: rgba(0, 0, 0, 0); - filter: alpha(opacity=50); - opacity: .5; -} -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); - background-repeat: repeat-x; -} -.carousel-control.right { - right: 0; - left: auto; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); - background-repeat: repeat-x; -} -.carousel-control:hover, -.carousel-control:focus { - color: #fff; - text-decoration: none; - filter: alpha(opacity=90); - outline: 0; - opacity: .9; -} -.carousel-control .icon-prev, -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-left, -.carousel-control .glyphicon-chevron-right { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block; - margin-top: -10px; -} -.carousel-control .icon-prev, -.carousel-control .glyphicon-chevron-left { - left: 50%; - margin-left: -10px; -} -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-right { - right: 50%; - margin-right: -10px; -} -.carousel-control .icon-prev, -.carousel-control .icon-next { - width: 20px; - height: 20px; - font-family: serif; - line-height: 1; -} -.carousel-control .icon-prev:before { - content: '\2039'; -} -.carousel-control .icon-next:before { - content: '\203a'; -} -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - padding-left: 0; - margin-left: -30%; - text-align: center; - list-style: none; -} -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); - border: 1px solid #fff; - border-radius: 10px; -} -.carousel-indicators .active { - width: 12px; - height: 12px; - margin: 0; - background-color: #fff; -} -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); -} -.carousel-caption .btn { - text-shadow: none; -} -@media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-prev, - .carousel-control .icon-next { - width: 30px; - height: 30px; - margin-top: -10px; - font-size: 30px; - } - .carousel-control .glyphicon-chevron-left, - .carousel-control .icon-prev { - margin-left: -10px; - } - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next { - margin-right: -10px; - } - .carousel-caption { - right: 20%; - left: 20%; - padding-bottom: 30px; - } - .carousel-indicators { - bottom: 20px; - } -} -.clearfix:before, -.clearfix:after, -.dl-horizontal dd:before, -.dl-horizontal dd:after, -.container:before, -.container:after, -.container-fluid:before, -.container-fluid:after, -.row:before, -.row:after, -.form-horizontal .form-group:before, -.form-horizontal .form-group:after, -.btn-toolbar:before, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after, -.nav:before, -.nav:after, -.navbar:before, -.navbar:after, -.navbar-header:before, -.navbar-header:after, -.navbar-collapse:before, -.navbar-collapse:after, -.pager:before, -.pager:after, -.panel-body:before, -.panel-body:after, -.modal-header:before, -.modal-header:after, -.modal-footer:before, -.modal-footer:after { - display: table; - content: " "; -} -.clearfix:after, -.dl-horizontal dd:after, -.container:after, -.container-fluid:after, -.row:after, -.form-horizontal .form-group:after, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:after, -.nav:after, -.navbar:after, -.navbar-header:after, -.navbar-collapse:after, -.pager:after, -.panel-body:after, -.modal-header:after, -.modal-footer:after { - clear: both; -} -.center-block { - display: block; - margin-right: auto; - margin-left: auto; -} -.pull-right { - float: right !important; -} -.pull-left { - float: left !important; -} -.hide { - display: none !important; -} -.show { - display: block !important; -} -.invisible { - visibility: hidden; -} -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.hidden { - display: none !important; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.visible-xs, -.visible-sm, -.visible-md, -.visible-lg { - display: none !important; -} -.visible-xs-block, -.visible-xs-inline, -.visible-xs-inline-block, -.visible-sm-block, -.visible-sm-inline, -.visible-sm-inline-block, -.visible-md-block, -.visible-md-inline, -.visible-md-inline-block, -.visible-lg-block, -.visible-lg-inline, -.visible-lg-inline-block { - display: none !important; -} -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table !important; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} -@media (max-width: 767px) { - .visible-xs-block { - display: block !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table !important; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table !important; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important; - } -} -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table !important; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important; - } -} -@media (max-width: 767px) { - .hidden-xs { - display: none !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important; - } -} -@media (min-width: 1200px) { - .hidden-lg { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table !important; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } -} -.visible-print-block { - display: none !important; -} -@media print { - .visible-print-block { - display: block !important; - } -} -.visible-print-inline { - display: none !important; -} -@media print { - .visible-print-inline { - display: inline !important; - } -} -.visible-print-inline-block { - display: none !important; -} -@media print { - .visible-print-inline-block { - display: inline-block !important; - } -} -@media print { - .hidden-print { - display: none !important; - } -} -/*# sourceMappingURL=bootstrap.css.map */ diff --git a/bomberman/frontend/src/main/webapp/css/style.css b/bomberman/frontend/src/main/webapp/css/style.css deleted file mode 100644 index 672d36dba3..0000000000 --- a/bomberman/frontend/src/main/webapp/css/style.css +++ /dev/null @@ -1,52 +0,0 @@ - .container { - width: 545px; -} - -#game { - margin: auto; - text-align: center; -} - -.footer .alert { - text-align: center; - line-height: 35px; -} - -.footer .alert img { - margin-top: -3px; - margin-right: 5px; -} - -h1 { - line-height: 64px; - margin-bottom: 0; -} - -.html5 { - width: 64px; - height: 64px; - display: block; - float: left; - margin-right: 10px; -} - -.html5 span { - display: none; -} - -h1 strong { - color: #FF4444; -} - -.credits { - color: gray; -} - -.credits a { - color: gray; - text-decoration: underline; -} - -.credits a:hover { - color: black; -} \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/favicon.ico b/bomberman/frontend/src/main/webapp/favicon.ico deleted file mode 100644 index 9fa3a0198c..0000000000 Binary files a/bomberman/frontend/src/main/webapp/favicon.ico and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/betty.png b/bomberman/frontend/src/main/webapp/img/betty.png deleted file mode 100644 index f62ae8b42d..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/betty.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/betty2.png b/bomberman/frontend/src/main/webapp/img/betty2.png deleted file mode 100644 index e2c12eb695..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/betty2.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/bomb.png b/bomberman/frontend/src/main/webapp/img/bomb.png deleted file mode 100644 index dcd2f9c83b..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/bomb.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/bomberman.png b/bomberman/frontend/src/main/webapp/img/bomberman.png deleted file mode 100644 index 3aff57dc20..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/bomberman.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/bonuses.png b/bomberman/frontend/src/main/webapp/img/bonuses.png deleted file mode 100644 index 72e8da257e..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/bonuses.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/fire.png b/bomberman/frontend/src/main/webapp/img/fire.png deleted file mode 100644 index 8394bcbd5b..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/fire.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/george.png b/bomberman/frontend/src/main/webapp/img/george.png deleted file mode 100644 index 6e58db5a71..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/george.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/github.png b/bomberman/frontend/src/main/webapp/img/github.png deleted file mode 100644 index d5f4488590..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/github.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/rpg_character.png b/bomberman/frontend/src/main/webapp/img/rpg_character.png deleted file mode 100644 index b18f94950c..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/rpg_character.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/tile_grass.png b/bomberman/frontend/src/main/webapp/img/tile_grass.png deleted file mode 100644 index b0d192305e..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/tile_grass.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/tile_wall.png b/bomberman/frontend/src/main/webapp/img/tile_wall.png deleted file mode 100644 index 0468c17752..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/tile_wall.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/img/tile_wood.png b/bomberman/frontend/src/main/webapp/img/tile_wood.png deleted file mode 100644 index 07d44d9d5d..0000000000 Binary files a/bomberman/frontend/src/main/webapp/img/tile_wood.png and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/index.html b/bomberman/frontend/src/main/webapp/index.html deleted file mode 100644 index 06b9de0b5d..0000000000 --- a/bomberman/frontend/src/main/webapp/index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - Bombergirl - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - -
-

How to play

- - M … mute / unmute sound
- enter … restart
- escape … menu - -
- - -
- - \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Bomb.js b/bomberman/frontend/src/main/webapp/js/Bomb.js deleted file mode 100644 index c820b0dd6e..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Bomb.js +++ /dev/null @@ -1,71 +0,0 @@ -Bomb = Entity.extend({ - /** - * Entity position on map grid - */ - position: {}, - - /** - * How far the fire reaches when bomb explodes - */ - strength: 1, - - /** - * Bitmap dimensions - */ - size: { - w: 28, - h: 28 - }, - - /** - * Bitmap animation - */ - bmp: null, - - /** - * Timer in frames - */ - timer: 0, - - /** - * Max timer value in seconds - */ - timerMax: 2, - - exploded: false, - - fires: [], - - explodeListener: null, - - init: function(id, position, strength) { - this.id = id; - this.strength = strength; - - var spriteSheet = new createjs.SpriteSheet({ - images: [gGameEngine.bombImg], - frames: { - width: this.size.w, - height: this.size.h, - regX: 5, - regY: 5 - }, - animations: { - idle: [0, 4, "idle", 0.2] - } - }); - this.bmp = new createjs.Sprite(spriteSheet); - this.bmp.gotoAndPlay('idle'); - - this.position = position; - this.bmp.x = position.x; - this.bmp.y = position.y; - - this.fires = []; - gGameEngine.stage.addChild(this.bmp); - }, - - remove: function() { - gGameEngine.stage.removeChild(this.bmp); - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Bonus.js b/bomberman/frontend/src/main/webapp/js/Bonus.js deleted file mode 100644 index 4a4c6a1e45..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Bonus.js +++ /dev/null @@ -1,24 +0,0 @@ -Bonus = Entity.extend({ - types: ['speed', 'bomb', 'fire'], - - type: '', - position: {}, - bmp: null, - - init: function(position, typePosition) { - this.type = this.types[typePosition]; - - this.position = position; - - this.bmp = new createjs.Bitmap(gGameEngine.bonusesImg); - var pixels = Utils.convertToBitmapPosition(position); - this.bmp.x = pixels.x; - this.bmp.y = pixels.y; - this.bmp.sourceRect = new createjs.Rectangle(typePosition * 32, 0, 32, 32); - gGameEngine.stage.addChild(this.bmp); - }, - - remove: function() { - gGameEngine.stage.removeChild(this.bmp); - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Entity.js b/bomberman/frontend/src/main/webapp/js/Entity.js deleted file mode 100644 index 43f53e4faf..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Entity.js +++ /dev/null @@ -1,12 +0,0 @@ -Entity = Class.extend({ - id: null, - - init: function() { - }, - - update: function() { - }, - - remove: function () { - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Fire.js b/bomberman/frontend/src/main/webapp/js/Fire.js deleted file mode 100644 index 495192fda5..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Fire.js +++ /dev/null @@ -1,50 +0,0 @@ -Fire = Entity.extend({ - /** - * Entity position on map grid - */ - position: {}, - - /** - * Bitmap dimensions - */ - size: { - w: 38, - h: 38 - }, - - /** - * Bitmap animation - */ - bmp: null, - - init: function(id, position) { - this.id = id; - var spriteSheet = new createjs.SpriteSheet({ - images: [gGameEngine.fireImg], - frames: { width: this.size.w, height: this.size.h, regX: 0, regY: 0 }, - animations: { - idle: [0, 5, null, 0.4], - } - }); - this.bmp = new createjs.Sprite(spriteSheet); - this.bmp.gotoAndPlay('idle'); - var that = this; - this.bmp.addEventListener('animationend', function() { - that.remove(); - }); - - this.position = position; - - this.bmp.x = position.x + 2; - this.bmp.y = position.y - 5; - - gGameEngine.stage.addChild(this.bmp); - }, - - update: function() { - }, - - remove: function() { - gGameEngine.stage.removeChild(this.bmp); - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/GameEngine.js b/bomberman/frontend/src/main/webapp/js/GameEngine.js deleted file mode 100644 index 163c3c213a..0000000000 --- a/bomberman/frontend/src/main/webapp/js/GameEngine.js +++ /dev/null @@ -1,204 +0,0 @@ -GameEngine = Class.extend({ - tileSize: 32, - tilesX: 17, - tilesY: 13, - size: {}, - fps: 60, - playersCount: 2, - bonusesPercent: 16, - - stage: null, - menu: null, - players: [], - tiles: [], - bombs: [], - bonuses: [], - fires: [], - - playerBoyImg: null, - playerGirlImg: null, - playerGirl2Img: null, - tilesImgs: {}, - bombImg: null, - fireImg: null, - bonusesImg: null, - - playing: false, - mute: false, - soundtrackLoaded: false, - soundtrackPlaying: false, - soundtrack: null, - - serverProxy: null, - - init: function() { - this.size = { - w: this.tileSize * this.tilesX, - h: this.tileSize * this.tilesY - }; - }, - - load: function() { - // Init canvas - this.stage = new createjs.Stage("canvas"); - this.stage.enableMouseOver(); - - // Load assets - var queue = new createjs.LoadQueue(); - var that = this; - queue.addEventListener("complete", function() { - that.playerBoyImg = queue.getResult("playerBoy"); - that.playerGirlImg = queue.getResult("playerGirl"); - that.playerGirl2Img = queue.getResult("playerGirl2"); - that.tilesImgs.grass = queue.getResult("tile_grass"); - that.tilesImgs.wall = queue.getResult("tile_wall"); - that.tilesImgs.wood = queue.getResult("tile_wood"); - that.bombImg = queue.getResult("bomb"); - that.fireImg = queue.getResult("fire"); - that.bonusesImg = queue.getResult("bonuses"); - that.setup(); - }); - queue.loadManifest([ - {id: "playerBoy", src: "img/george.png"}, - {id: "playerGirl", src: "img/betty.png"}, - {id: "playerGirl2", src: "img/betty2.png"}, - {id: "tile_grass", src: "img/tile_grass.png"}, - {id: "tile_wall", src: "img/tile_wall.png"}, - {id: "tile_wood", src: "img/tile_wood.png"}, - {id: "bomb", src: "img/bomb.png"}, - {id: "fire", src: "img/fire.png"}, - {id: "bonuses", src: "img/bonuses.png"} - ]); - - createjs.Sound.addEventListener("fileload", this.onSoundLoaded); - createjs.Sound.alternateExtensions = ["mp3"]; - createjs.Sound.registerSound("sound/bomb.ogg", "bomb"); - // createjs.Sound.registerSound("sound/game.ogg", "game"); - - this.menu = new Menu(); - }, - - setup: function() { - if (!gInputEngine.bindings.length) { - gInputEngine.setup(); - } - - this.bombs = []; - this.tiles = []; - this.bonuses = []; - - this.serverProxy = new ServerProxy(); - - // Toggle sound - gInputEngine.subscribe('mute', this.toggleSound); - - // Start loop - if (!createjs.Ticker.hasEventListener('tick')) { - createjs.Ticker.addEventListener('tick', gGameEngine.update); - createjs.Ticker.setFPS(this.fps); - } - - if (gGameEngine.playersCount > 0) { - if (this.soundtrackLoaded) { - this.playSoundtrack(); - } - } - - if (!this.playing) { - this.menu.show(); - } - }, - - onSoundLoaded: function(sound) { - if (sound.id == 'game') { - gGameEngine.soundtrackLoaded = true; - if (gGameEngine.playersCount > 0) { - gGameEngine.playSoundtrack(); - } - } - }, - - playSoundtrack: function() { - if (!gGameEngine.soundtrackPlaying) { - gGameEngine.soundtrack = createjs.Sound.play("game", "none", 0, 0, -1); - gGameEngine.soundtrack.setVolume(1); - gGameEngine.soundtrackPlaying = true; - } - }, - - update: function() { - // Player - for (var i = 0; i < gGameEngine.players.length; i++) { - var player = gGameEngine.players[i]; - player.update(); - } - - // Bombs - for (var i = 0; i < gGameEngine.bombs.length; i++) { - var bomb = gGameEngine.bombs[i]; - bomb.update(); - } - - // Menu - gGameEngine.menu.update(); - - // Stage - gGameEngine.stage.update(); - }, - - // gameOver: function(status) { - // if (gGameEngine.menu.visible) { return; } - // - // if (status == 'win') { - // var winText = "You won!"; - // if (gGameEngine.playersCount > 1) { - // var winner = gGameEngine.getWinner(); - // winText = winner == 0 ? "Player 1 won!" : "Player 2 won!"; - // } - // this.menu.show([{text: winText, color: '#669900'}, {text: ' ;D', color: '#99CC00'}]); - // } else { - // this.menu.show([{text: 'Game Over', color: '#CC0000'}, {text: ' :(', color: '#FF4444'}]); - // } - // }, - - restart: function() { - // gInputEngine.removeAllListeners(); - gGameEngine.stage.removeAllChildren(); - gGameEngine.setup(); - this.serverProxy = new ServerProxy(); - }, - - /** - * Moves specified child to the front. - */ - moveToFront: function(child) { - var children = gGameEngine.stage.getNumChildren(); - gGameEngine.stage.setChildIndex(child, children - 1); - }, - - toggleSound: function() { - if (gGameEngine.mute) { - gGameEngine.mute = false; - gGameEngine.soundtrack.resume(); - } else { - gGameEngine.mute = true; - gGameEngine.soundtrack.pause(); - } - }, - - gc: function(survivors) { - [this.players, this.tiles, this.bombs, this.bonuses].forEach(function (it) { - var i = it.length; - while (i--) { - if (!survivors.has(it[i].id)) { - it[i].remove(); - it.splice(i, 1); - } - } - }); - - } - -}); - -gGameEngine = new GameEngine(); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/InputEngine.js b/bomberman/frontend/src/main/webapp/js/InputEngine.js deleted file mode 100644 index f9600c9052..0000000000 --- a/bomberman/frontend/src/main/webapp/js/InputEngine.js +++ /dev/null @@ -1,132 +0,0 @@ -InputEngine = Class.extend({ - - // move notification fps - fps: 60, - - /** - * A dictionary mapping ASCII key codes to string values describing - * the action we want to take when that key is pressed. - */ - bindings: {}, - - /** - * A dictionary mapping actions that might be taken in our game - * to a boolean value indicating whether that action is currently being performed. - */ - actions: {}, - - possessed: null, - - subscribers: [], - - init: function() { }, - - setup: function() { - this.bind(37, 'left'); - this.bind(38, 'up'); - this.bind(39, 'right'); - this.bind(40, 'down'); - - - this.bind(32, 'bomb'); - - this.bind(13, 'restart'); - this.bind(27, 'escape'); - this.bind(77, 'mute'); - - // move multiple presses with fps frequency - this.keyboardController({ - 37 : this.onKeyDown, - 38 : this.onKeyDown, - 39 : this.onKeyDown, - 40 : this.onKeyDown - }, 1000 / this.fps); - - document.addEventListener('keydown', this.onKeyDown); - document.addEventListener('keyup', this.onKeyUp); - }, - - onKeyUp: function(event) { - var action = gInputEngine.bindings[event.keyCode]; - if (action) { - gInputEngine.actions[action] = false; - event.preventDefault(); - } - return false; - }, - - onKeyDown: function(event) { - var action = gInputEngine.bindings[event.keyCode]; - if (action) { - gInputEngine.actions[action] = true; - var subscribers = gInputEngine.subscribers[action]; - if (subscribers) { - for (var i = 0; i < subscribers.length; i++ ) { - subscribers[i]() - } - } - - event.preventDefault(); - } - return false; - }, - - /** - * The bind function takes an ASCII keycode and a string representing - * the action to take when that key is pressed. - */ - bind: function(key, action) { - this.bindings[key] = action; - }, - - subscribe: function (action, callback) { - this.subscribers[action] = this.subscribers[action] || []; - this.subscribers[action].push(callback) - }, - - // Keyboard input with customisable repeat (set to 0 for no key repeat) - keyboardController: function(keys, repeat) { - - // Lookup of key codes to timer ID, or null for no repeat - var timers = {}; - - // When key is pressed and we don't already think it's pressed, call the - // key action callback and set a timer to generate another one after a delay - document.onkeydown= function(event) { - var key = (event || window.event).keyCode; - if (!(key in keys)) - return true; - if (!(key in timers)) { - timers[key] = null; - keys[key](event); - if (repeat !== 0) - var f = function () { - keys[key](event); - }; - timers[key]= setInterval(f, repeat); - } - return false; - }; - - // Cancel timeout and mark key as released on keyup - document.onkeyup = function(event) { - var key= (event || window.event).keyCode; - if (key in timers) { - if (timers[key] !== null) - clearInterval(timers[key]); - delete timers[key]; - } - }; - - // When window is unfocused we may not get key events. To prevent this - // causing a key to 'get stuck down', cancel all held keys - window.onblur = function() { - for (key in timers) - if (timers[key] !== null) - clearInterval(timers[key]); - timers= {}; - }; - } -}); - -gInputEngine = new InputEngine(); diff --git a/bomberman/frontend/src/main/webapp/js/Menu.js b/bomberman/frontend/src/main/webapp/js/Menu.js deleted file mode 100644 index 4cdbdea3c1..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Menu.js +++ /dev/null @@ -1,106 +0,0 @@ -Menu = Class.extend({ - visible: true, - - views: [], - - init: function () { - gGameEngine.playersCount = 0; - - this.showLoader(); - }, - - show: function (text) { - this.visible = true; - - this.draw(text); - }, - - hide: function () { - this.visible = false; - - for (var i = 0; i < this.views.length; i++) { - gGameEngine.stage.removeChild(this.views[i]); - } - - this.views = []; - }, - - update: function () { - if (this.visible) { - for (var i = 0; i < this.views.length; i++) { - gGameEngine.moveToFront(this.views[i]); - } - } - }, - - setHandCursor: function (btn) { - btn.addEventListener('mouseover', function () { - document.body.style.cursor = 'pointer'; - }); - btn.addEventListener('mouseout', function () { - document.body.style.cursor = 'auto'; - }); - }, - - start: function () { - this.hide(); - - gGameEngine.playing = true; - gGameEngine.serverProxy.getSessionIdFromMatchMaker(); - gGameEngine.restart(); - }, - - draw: function (text) { - var that = this; - - // semi-transparent black background - var bgGraphics = new createjs.Graphics().beginFill("rgba(0, 0, 0, 0.5)").drawRect(0, 0, gGameEngine.size.w, gGameEngine.size.h); - var bg = new createjs.Shape(bgGraphics); - gGameEngine.stage.addChild(bg); - this.views.push(bg); - - - // start button - var startButtonX = gGameEngine.size.w / 2 - 55; - var startButtonY = gGameEngine.size.h / 2 - 80; - var startButtonSize = 110; - - var singleBgGraphics = new createjs.Graphics().beginFill("rgba(0, 0, 0, 0.5)").drawRect(startButtonX, startButtonY, startButtonSize, startButtonSize); - var singleBg = new createjs.Shape(singleBgGraphics); - gGameEngine.stage.addChild(singleBg); - this.views.push(singleBg); - this.setHandCursor(singleBg); - singleBg.addEventListener('click', function () { - that.start(); - }); - - var playButton = new createjs.Text("Play", "32px Helvetica", "#ff4444"); - var singleTitleWidth = playButton.getMeasuredWidth(); - var modeTitlesY = startButtonY + startButtonSize - playButton.getMeasuredHeight() - 20; - - playButton.x = startButtonX + (startButtonSize - singleTitleWidth) / 2; - playButton.y = modeTitlesY; - gGameEngine.stage.addChild(playButton); - this.views.push(playButton); - - var iconsY = startButtonY + 13; - var singleIcon = new createjs.Bitmap("img/betty.png"); - singleIcon.sourceRect = new createjs.Rectangle(0, 0, 48, 48); - singleIcon.x = startButtonX + (startButtonSize - 48) / 2; - singleIcon.y = iconsY; - gGameEngine.stage.addChild(singleIcon); - this.views.push(singleIcon); - }, - - showLoader: function () { - var bgGraphics = new createjs.Graphics().beginFill("#000000").drawRect(0, 0, gGameEngine.size.w, gGameEngine.size.h); - var bg = new createjs.Shape(bgGraphics); - gGameEngine.stage.addChild(bg); - - var loadingText = new createjs.Text("Loading...", "20px Helvetica", "#FFFFFF"); - loadingText.x = gGameEngine.size.w / 2 - loadingText.getMeasuredWidth() / 2; - loadingText.y = gGameEngine.size.h / 2 - loadingText.getMeasuredHeight() / 2 - 150; - gGameEngine.stage.addChild(loadingText); - gGameEngine.stage.update(); - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Message.js b/bomberman/frontend/src/main/webapp/js/Message.js deleted file mode 100644 index 467e2ef8a5..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Message.js +++ /dev/null @@ -1,112 +0,0 @@ -Messages = Class.extend({ - handler: {}, - - init: function () { - this.handler['Pawn'] = this.handlePawn; - this.handler['Bomb'] = this.handleBomb; - this.handler['Wood'] = this.handleTile; - this.handler['Wall'] = this.handleTile; - this.handler['Fire'] = this.handleFire; - }, - - move: function (direction) { - var template = { - topic: "MOVE", - data: {} - }; - - template.data.direction = direction.toUpperCase(); - return JSON.stringify(template); - }, - - plantBomb: function () { - var template = { - topic: "PLANT_BOMB", - data: {} - }; - - return JSON.stringify(template); - }, - - - handleReplica: function (msg) { - //var gameObjects = JSON.parse(msg.data).objects - var gameObjects = msg.data.objects; - var survivors = new Set(); - - for (var i = 0; i < gameObjects.length; i++) { - var obj = gameObjects[i]; - if (gMessages.handler[obj.type] === undefined) - continue; - - survivors.add(obj.id); - gMessages.handler[obj.type](obj); - } - gGameEngine.gc(survivors); - }, - - handlePossess: function (msg) { - gInputEngine.possessed = parseInt(msg.data); - }, - - handlePawn: function(obj) { - var player = gGameEngine.players.find(function (el) { - return el.id === obj.id; - }); - var position = Utils.getEntityPosition(obj.position); - - if (player) { - player.bmp.x = position.x; - player.bmp.y = position.y; - } else { - console.log(new Date().getTime() + " handel new player " + obj.id); - player = new Player(obj.id, position); - gGameEngine.players.push(player); - } - }, - - handleBomb: function(obj) { - var bomb = gGameEngine.bombs.find(function (el) { - return el.id === obj.id; - }); - var position = Utils.getEntityPosition(obj.position); - - if (bomb) { - bomb.bmp.x = position.x; - bomb.bmp.y = position.y; - } else { - bomb = new Bomb(obj.id, position); - gGameEngine.bombs.push(bomb); - } - }, - - handleTile: function (obj) { - var tile = gGameEngine.tiles.find(function (el) { - return el.id === obj.id; - }); - - //var position = Utils.getEntityPosition(Utils.convertToBitmapPosition(obj.position)); - var position = Utils.getEntityPosition(obj.position); - if (tile) { - tile.material = obj.type; - } else { - tile = new Tile(obj.id, obj.type, position); - gGameEngine.tiles.push(tile); - } - }, - - handleFire: function (obj) { - var fire = gGameEngine.fires.find(function (el) { - return el.id === obj.id; - }); - - var position = Utils.getEntityPosition(obj.position); - if (!fire) { - fire = new Fire(obj.id, position); - gGameEngine.fires.push(fire); - } - } - -}); - -gMessages = new Messages(); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Player.js b/bomberman/frontend/src/main/webapp/js/Player.js deleted file mode 100644 index 486a17a8ad..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Player.js +++ /dev/null @@ -1,117 +0,0 @@ -Player = Entity.extend({ - /** - * Bitmap dimensions - */ - size: { - w: 48, - h: 48 - }, - - /** - * Bitmap animation - */ - bmp: null, - - alive: true, - - bombs: [], - - controls: { - 'up': 'up', - 'left': 'left', - 'down': 'down', - 'right': 'right', - 'bomb': 'bomb' - }, - - /** - * Bomb that player can escape from even when there is a collision - */ - escapeBomb: null, - - deadTimer: 0, - - - - init: function(id, position) { - this.id = id; - - var img = gGameEngine.playerGirlImg; - - var spriteSheet = new createjs.SpriteSheet({ - images: [img], - frames: { width: this.size.w, height: this.size.h, regX: 10, regY: 12 }, - animations: { - idle: [0, 0, 'idle'], - down: [0, 3, 'down', 0.1], - left: [4, 7, 'left', 0.1], - up: [8, 11, 'up', 0.1], - right: [12, 15, 'right', 0.1], - dead: [16, 16, 'dead', 0.1] - } - }); - this.bmp = new createjs.Sprite(spriteSheet); - - this.bmp.x = position.x; - this.bmp.y = position.y; - - gGameEngine.stage.addChild(this.bmp); - - this.bombs = []; - }, - - - update: function() { - if (!this.alive) { - return; - } - - if (gInputEngine.possessed !== this.id) { - return; - } - - if (gInputEngine.actions[this.controls.up]) { - this.animate('up'); - } else if (gInputEngine.actions[this.controls.down]) { - this.animate('down'); - } else if (gInputEngine.actions[this.controls.left]) { - this.animate('left'); - } else if (gInputEngine.actions[this.controls.right]) { - this.animate('right'); - } else { - this.animate('idle'); - } - }, - - /** - * Changes animation if requested animation is not already current. - */ - animate: function(animation) { - if (!this.bmp.currentAnimation || this.bmp.currentAnimation.indexOf(animation) === -1) { - this.bmp.gotoAndPlay(animation); - } - }, - - die: function() { - this.alive = false; - - this.bmp.gotoAndPlay('dead'); - this.fade(); - }, - - fade: function() { - var timer = 0; - var bmp = this.bmp; - var fade = setInterval(function() { - timer++; - - if (timer > 30) { - bmp.alpha -= 0.05; - } - if (bmp.alpha <= 0) { - clearInterval(fade); - } - - }, 30); - } -}); diff --git a/bomberman/frontend/src/main/webapp/js/ServerProxy.js b/bomberman/frontend/src/main/webapp/js/ServerProxy.js deleted file mode 100644 index 53bfc190d1..0000000000 --- a/bomberman/frontend/src/main/webapp/js/ServerProxy.js +++ /dev/null @@ -1,91 +0,0 @@ -ServerProxy = Class.extend({ - gameServerUrl: "localhost:8090", - matchMakerUrl: "localhost:8080/matchmaker/join", - gameId: "1234", - - socket: null, - - handler: {}, - - init: function () { - this.handler['REPLICA'] = gMessages.handleReplica; - this.handler['POSSESS'] = gMessages.handlePossess; - - var self = this; - gInputEngine.subscribe('up', function () { - self.socket.send(gMessages.move('up')) - }); - gInputEngine.subscribe('down', function () { - self.socket.send(gMessages.move('down')) - }); - gInputEngine.subscribe('left', function () { - self.socket.send(gMessages.move('left')) - }); - gInputEngine.subscribe('right', function () { - self.socket.send(gMessages.move('right')) - }); - gInputEngine.subscribe('bomb', function () { - self.socket.send(gMessages.plantBomb()) - }); - }, - - getSessionIdFromMatchMaker: function () { - var that = this; - var login = $("#loginInput").val(); - if(!login){ - alert("Please input login"); - console.log("Empty login, retry login"); - } - $.ajax({ - contentType: 'application/x-www-form-urlencoded', - data: { - "name": login - }, - dataType: 'text', - success: function(data){ - that.gameId=data; - console.log("Matchmaker returned gameId=" + data); - that.connectToGameServer(that.gameId, login); - }, - error: function(){ - alert("Matchmaker request failed, use default gameId=" + that.gameId); - console.log("Matchmaker request failed, use default gameId=" + that.gameId); - that.connectToGameServer(that.gameId, login); - }, - //processData: false - type: 'POST', - url: that.matchMakerUrl - }); - }, - - connectToGameServer: function (gameId, login) { - var self = this; - this.socket = new WebSocket("ws://" + this.gameServerUrl + "/game/connect?gameId=" + gameId + "&name=" + login); - - this.socket.onopen = function () { - console.log("Connection established."); - }; - - this.socket.onclose = function (event) { - if (event.wasClean) { - console.log('closed'); - } else { - console.log('alert close'); - } - console.log('Code: ' + event.code + ' cause: ' + event.reason); - }; - - this.socket.onmessage = function (event) { - var msg = JSON.parse(event.data); - if (self.handler[msg.topic] === undefined) - return; - - self.handler[msg.topic](msg); - }; - - this.socket.onerror = function (error) { - console.log("Error " + error.message); - }; - } - -}); diff --git a/bomberman/frontend/src/main/webapp/js/Tile.js b/bomberman/frontend/src/main/webapp/js/Tile.js deleted file mode 100644 index b0e0f2a6aa..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Tile.js +++ /dev/null @@ -1,48 +0,0 @@ -Tile = Entity.extend({ - /** - * Entity position on map grid - */ - position: {}, - - /** - * Bitmap dimensions - */ - size: { - w: 32, - h: 32 - }, - - /** - * Bitmap animation - */ - bmp: null, - - material: '', - - init: function(id, material, position) { - this.id = id; - this.material = material; - this.position = position; - var img; - if (material == 'grass') { - img = gGameEngine.tilesImgs.grass; - } else if (material === 'Wall') { - img = gGameEngine.tilesImgs.wall; - } else if (material === 'Wood') { - img = gGameEngine.tilesImgs.wood; - } - this.bmp = new createjs.Bitmap(img); - - this.bmp.x = position.x; - this.bmp.y = position.y; - - gGameEngine.stage.addChild(this.bmp); - }, - - update: function() { - }, - - remove: function() { - gGameEngine.stage.removeChild(this.bmp); - } -}); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/Utils.js b/bomberman/frontend/src/main/webapp/js/Utils.js deleted file mode 100644 index 35446f8049..0000000000 --- a/bomberman/frontend/src/main/webapp/js/Utils.js +++ /dev/null @@ -1,48 +0,0 @@ -var Utils = {}; - -/** - * Returns true if positions are equal. - */ -Utils.comparePositions = function(pos1, pos2) { - return pos1.x == pos2.x && pos1.y == pos2.y; -}; - - -/** - * Convert bitmap pixels position to entity on grid position. - */ -Utils.convertToEntityPosition = function(pixels) { - var position = {}; - position.x = Math.round(pixels.x / gGameEngine.tileSize); - position.y = Math.round(pixels.y /gGameEngine.tileSize); - return position; -}; - -Utils.getEntityPosition = function (pixels) { - var position = {}; - position.x = pixels.x; - position.y = -pixels.y + 12 * 32; - return position; -} - -/** - * Convert entity on grid position to bitmap pixels position. - */ -Utils.convertToBitmapPosition = function(entity) { - var position = {}; - position.x = entity.x * gGameEngine.tileSize; - position.y = entity.y * gGameEngine.tileSize; - return position; -}; - -/** - * Removes an item from array. - */ -Utils.removeFromArray = function(array, item) { - for (var i = 0; i < array.length; i++) { - if (item == array[i]) { - array.splice(i, 1); - } - } - return array; -}; \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/core.js b/bomberman/frontend/src/main/webapp/js/core.js deleted file mode 100644 index 31f5105790..0000000000 --- a/bomberman/frontend/src/main/webapp/js/core.js +++ /dev/null @@ -1,64 +0,0 @@ -/* Simple JavaScript Inheritance - * By John Resig http://ejohn.org/ - * MIT Licensed. - */ -// Inspired by base2 and Prototype -(function(){ - var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; - - // The base Class implementation (does nothing) - this.Class = function(){}; - - // Create a new Class that inherits from this class - Class.extend = function(prop) { - var _super = this.prototype; - - // Instantiate a base class (but only create the instance, - // don't run the init constructor) - initializing = true; - var prototype = new this(); - initializing = false; - - // Copy the properties over onto the new prototype - for (var name in prop) { - // Check if we're overwriting an existing function - prototype[name] = typeof prop[name] == "function" && - typeof _super[name] == "function" && fnTest.test(prop[name]) ? - (function(name, fn){ - return function() { - var tmp = this._super; - - // Add a new ._super() method that is the same method - // but on the super-class - this._super = _super[name]; - - // The method only need to be bound temporarily, so we - // remove it when we're done executing - var ret = fn.apply(this, arguments); - this._super = tmp; - - return ret; - }; - })(name, prop[name]) : - prop[name]; - } - - // The dummy class constructor - function Class() { - // All construction is actually done in the init method - if ( !initializing && this.init ) - this.init.apply(this, arguments); - } - - // Populate our constructed prototype object - Class.prototype = prototype; - - // Enforce the constructor to be what we expect - Class.prototype.constructor = Class; - - // And make this class extendable - Class.extend = arguments.callee; - - return Class; - }; -})(); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js b/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js deleted file mode 100644 index 6f2e17b093..0000000000 --- a/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js +++ /dev/null @@ -1,13413 +0,0 @@ -/*! -* EaselJS -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ - - -//############################################################################## -// extend.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Sets up the prototype chain and constructor property for a new class. - * - * This should be called right after creating the class constructor. - * - * function MySubClass() {} - * createjs.extend(MySubClass, MySuperClass); - * MySubClass.prototype.doSomething = function() { } - * - * var foo = new MySubClass(); - * console.log(foo instanceof MySuperClass); // true - * console.log(foo.prototype.constructor === MySubClass); // true - * - * @method extend - * @param {Function} subclass The subclass. - * @param {Function} superclass The superclass to extend. - * @return {Function} Returns the subclass's new prototype. - */ -createjs.extend = function(subclass, superclass) { - "use strict"; - - function o() { this.constructor = subclass; } - o.prototype = superclass.prototype; - return (subclass.prototype = new o()); -}; - -//############################################################################## -// promote.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. - * It is recommended to use the super class's name as the prefix. - * An alias to the super class's constructor is always added in the format `prefix_constructor`. - * This allows the subclass to call super class methods without using `function.call`, providing better performance. - * - * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` - * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the - * prototype of `MySubClass` as `MySuperClass_draw`. - * - * This should be called after the class's prototype is fully defined. - * - * function ClassA(name) { - * this.name = name; - * } - * ClassA.prototype.greet = function() { - * return "Hello "+this.name; - * } - * - * function ClassB(name, punctuation) { - * this.ClassA_constructor(name); - * this.punctuation = punctuation; - * } - * createjs.extend(ClassB, ClassA); - * ClassB.prototype.greet = function() { - * return this.ClassA_greet()+this.punctuation; - * } - * createjs.promote(ClassB, "ClassA"); - * - * var foo = new ClassB("World", "!?!"); - * console.log(foo.greet()); // Hello World!?! - * - * @method promote - * @param {Function} subclass The class to promote super class methods on. - * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. - * @return {Function} Returns the subclass. - */ -createjs.promote = function(subclass, prefix) { - "use strict"; - - var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; - if (supP) { - subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable - for (var n in supP) { - if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } - } - } - return subclass; -}; - -//############################################################################## -// indexOf.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of - * that value. Returns -1 if value is not found. - * - * var i = createjs.indexOf(myArray, myElementToFind); - * - * @method indexOf - * @param {Array} array Array to search for searchElement - * @param searchElement Element to find in array. - * @return {Number} The first index of searchElement in array. - */ -createjs.indexOf = function (array, searchElement){ - "use strict"; - - for (var i = 0,l=array.length; i < l; i++) { - if (searchElement === array[i]) { - return i; - } - } - return -1; -}; - -//############################################################################## -// Event.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - -// constructor: - /** - * Contains properties and methods shared by all events for use with - * {{#crossLink "EventDispatcher"}}{{/crossLink}}. - * - * Note that Event objects are often reused, so you should never - * rely on an event object's state outside of the call stack it was received in. - * @class Event - * @param {String} type The event type. - * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. - * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. - * @constructor - **/ - function Event(type, bubbles, cancelable) { - - - // public properties: - /** - * The type of event. - * @property type - * @type String - **/ - this.type = type; - - /** - * The object that generated an event. - * @property target - * @type Object - * @default null - * @readonly - */ - this.target = null; - - /** - * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will - * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event - * is generated from childObj, then a listener on parentObj would receive the event with - * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). - * @property currentTarget - * @type Object - * @default null - * @readonly - */ - this.currentTarget = null; - - /** - * For bubbling events, this indicates the current event phase:
    - *
  1. capture phase: starting from the top parent to the target
  2. - *
  3. at target phase: currently being dispatched from the target
  4. - *
  5. bubbling phase: from the target to the top parent
  6. - *
- * @property eventPhase - * @type Number - * @default 0 - * @readonly - */ - this.eventPhase = 0; - - /** - * Indicates whether the event will bubble through the display list. - * @property bubbles - * @type Boolean - * @default false - * @readonly - */ - this.bubbles = !!bubbles; - - /** - * Indicates whether the default behaviour of this event can be cancelled via - * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. - * @property cancelable - * @type Boolean - * @default false - * @readonly - */ - this.cancelable = !!cancelable; - - /** - * The epoch time at which this event was created. - * @property timeStamp - * @type Number - * @default 0 - * @readonly - */ - this.timeStamp = (new Date()).getTime(); - - /** - * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called - * on this event. - * @property defaultPrevented - * @type Boolean - * @default false - * @readonly - */ - this.defaultPrevented = false; - - /** - * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or - * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. - * @property propagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.propagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called - * on this event. - * @property immediatePropagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.immediatePropagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. - * @property removed - * @type Boolean - * @default false - * @readonly - */ - this.removed = false; - } - var p = Event.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - -// public methods: - /** - * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable. - * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will - * cancel the default behaviour associated with the event. - * @method preventDefault - **/ - p.preventDefault = function() { - this.defaultPrevented = this.cancelable&&true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopPropagation - **/ - p.stopPropagation = function() { - this.propagationStopped = true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and - * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopImmediatePropagation - **/ - p.stopImmediatePropagation = function() { - this.immediatePropagationStopped = this.propagationStopped = true; - }; - - /** - * Causes the active listener to be removed via removeEventListener(); - * - * myBtn.addEventListener("click", function(evt) { - * // do stuff... - * evt.remove(); // removes this listener. - * }); - * - * @method remove - **/ - p.remove = function() { - this.removed = true; - }; - - /** - * Returns a clone of the Event instance. - * @method clone - * @return {Event} a clone of the Event instance. - **/ - p.clone = function() { - return new Event(this.type, this.bubbles, this.cancelable); - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - * @method set - * @param {Object} props A generic object containing properties to copy to the instance. - * @return {Event} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Event (type="+this.type+")]"; - }; - - createjs.Event = Event; -}()); - -//############################################################################## -// EventDispatcher.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * EventDispatcher provides methods for managing queues of event listeners and dispatching events. - * - * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the - * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. - * - * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the - * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports - * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. - * - * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier - * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The - * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to - * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. - * - * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} - * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also - * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. - * - *

Example

- * Add EventDispatcher capabilities to the "MyClass" class. - * - * EventDispatcher.initialize(MyClass.prototype); - * - * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). - * - * instance.addEventListener("eventName", handlerMethod); - * function handlerMethod(event) { - * console.log(event.target + " Was Clicked"); - * } - * - * Maintaining proper scope
- * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} - * method to subscribe to events simplifies this. - * - * instance.addEventListener("click", function(event) { - * console.log(instance == this); // false, scope is ambiguous. - * }); - * - * instance.on("click", function(event) { - * console.log(instance == this); // true, "on" uses dispatcher scope by default. - * }); - * - * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage - * scope. - * - * Browser support - * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model - * requires modern browsers (IE9+). - * - * - * @class EventDispatcher - * @constructor - **/ - function EventDispatcher() { - - - // private properties: - /** - * @protected - * @property _listeners - * @type Object - **/ - this._listeners = null; - - /** - * @protected - * @property _captureListeners - * @type Object - **/ - this._captureListeners = null; - } - var p = EventDispatcher.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// static public methods: - /** - * Static initializer to mix EventDispatcher methods into a target object or prototype. - * - * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class - * EventDispatcher.initialize(myObject); // add to a specific instance - * - * @method initialize - * @static - * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a - * prototype. - **/ - EventDispatcher.initialize = function(target) { - target.addEventListener = p.addEventListener; - target.on = p.on; - target.removeEventListener = target.off = p.removeEventListener; - target.removeAllEventListeners = p.removeAllEventListeners; - target.hasEventListener = p.hasEventListener; - target.dispatchEvent = p.dispatchEvent; - target._dispatchEvent = p._dispatchEvent; - target.willTrigger = p.willTrigger; - }; - - -// public methods: - /** - * Adds the specified event listener. Note that adding multiple listeners to the same function will result in - * multiple callbacks getting fired. - * - *

Example

- * - * displayObject.addEventListener("click", handleClick); - * function handleClick(event) { - * // Click happened. - * } - * - * @method addEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function | Object} Returns the listener for chaining or assignment. - **/ - p.addEventListener = function(type, listener, useCapture) { - var listeners; - if (useCapture) { - listeners = this._captureListeners = this._captureListeners||{}; - } else { - listeners = this._listeners = this._listeners||{}; - } - var arr = listeners[type]; - if (arr) { this.removeEventListener(type, listener, useCapture); } - arr = listeners[type]; // remove may have deleted the array - if (!arr) { listeners[type] = [listener]; } - else { arr.push(listener); } - return listener; - }; - - /** - * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener - * only run once, associate arbitrary data with the listener, and remove the listener. - * - * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. - * The wrapper function is returned for use with `removeEventListener` (or `off`). - * - * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use - * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls - * to `on` with the same params will create multiple listeners. - * - *

Example

- * - * var listener = myBtn.on("click", handleClick, null, false, {count:3}); - * function handleClick(evt, data) { - * data.count -= 1; - * console.log(this == myBtn); // true - scope defaults to the dispatcher - * if (data.count == 0) { - * alert("clicked 3 times!"); - * myBtn.off("click", listener); - * // alternately: evt.remove(); - * } - * } - * - * @method on - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). - * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. - * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. - * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. - **/ - p.on = function(type, listener, scope, once, data, useCapture) { - if (listener.handleEvent) { - scope = scope||listener; - listener = listener.handleEvent; - } - scope = scope||this; - return this.addEventListener(type, function(evt) { - listener.call(scope, evt, data); - once&&evt.remove(); - }, useCapture); - }; - - /** - * Removes the specified event listener. - * - * Important Note: that you must pass the exact function reference used when the event was added. If a proxy - * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or - * closure will not work. - * - *

Example

- * - * displayObject.removeEventListener("click", handleClick); - * - * @method removeEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.removeEventListener = function(type, listener, useCapture) { - var listeners = useCapture ? this._captureListeners : this._listeners; - if (!listeners) { return; } - var arr = listeners[type]; - if (!arr) { return; } - for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See - * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example. - * - * @method off - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.off = p.removeEventListener; - - /** - * Removes all listeners for the specified type, or all listeners of all types. - * - *

Example

- * - * // Remove all listeners - * displayObject.removeAllEventListeners(); - * - * // Remove all click listeners - * displayObject.removeAllEventListeners("click"); - * - * @method removeAllEventListeners - * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. - **/ - p.removeAllEventListeners = function(type) { - if (!type) { this._listeners = this._captureListeners = null; } - else { - if (this._listeners) { delete(this._listeners[type]); } - if (this._captureListeners) { delete(this._captureListeners[type]); } - } - }; - - /** - * Dispatches the specified event to all listeners. - * - *

Example

- * - * // Use a string event - * this.dispatchEvent("complete"); - * - * // Use an Event instance - * var event = new createjs.Event("progress"); - * this.dispatchEvent(event); - * - * @method dispatchEvent - * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. - * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, - * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can - * be used to avoid event object instantiation for non-bubbling events that may not have any listeners. - * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj. - * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj. - * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise. - **/ - p.dispatchEvent = function(eventObj, bubbles, cancelable) { - if (typeof eventObj == "string") { - // skip everything if there's no listeners and it doesn't bubble: - var listeners = this._listeners; - if (!bubbles && (!listeners || !listeners[eventObj])) { return true; } - eventObj = new createjs.Event(eventObj, bubbles, cancelable); - } else if (eventObj.target && eventObj.clone) { - // redispatching an active event object, so clone it: - eventObj = eventObj.clone(); - } - - // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent - try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events - - if (!eventObj.bubbles || !this.parent) { - this._dispatchEvent(eventObj, 2); - } else { - var top=this, list=[top]; - while (top.parent) { list.push(top = top.parent); } - var i, l=list.length; - - // capture & atTarget - for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) { - list[i]._dispatchEvent(eventObj, 1+(i==0)); - } - // bubbling - for (i=1; iExample - * - * createjs.Ticker.addEventListener("tick", handleTick); - * function handleTick(event) { - * // Actions carried out each tick (aka frame) - * if (!event.paused) { - * // Actions carried out when the Ticker is not paused. - * } - * } - * - * @class Ticker - * @uses EventDispatcher - * @static - **/ - function Ticker() { - throw "Ticker cannot be instantiated."; - } - - -// constants: - /** - * In this mode, Ticker uses the requestAnimationFrame API, but attempts to synch the ticks to target framerate. It - * uses a simple heuristic that compares the time of the RAF return to the target time for the current frame and - * dispatches the tick when the time is within a certain threshold. - * - * This mode has a higher variance for time between frames than {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}}, - * but does not require that content be time based as with {{#crossLink "Ticker/RAF:property"}}{{/crossLink}} while - * gaining the benefits of that API (screen synch, background throttling). - * - * Variance is usually lowest for framerates that are a divisor of the RAF frequency. This is usually 60, so - * framerates of 10, 12, 15, 20, and 30 work well. - * - * Falls back to {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}} if the requestAnimationFrame API is not - * supported. - * @property RAF_SYNCHED - * @static - * @type {String} - * @default "synched" - * @readonly - **/ - Ticker.RAF_SYNCHED = "synched"; - - /** - * In this mode, Ticker passes through the requestAnimationFrame heartbeat, ignoring the target framerate completely. - * Because requestAnimationFrame frequency is not deterministic, any content using this mode should be time based. - * You can leverage {{#crossLink "Ticker/getTime"}}{{/crossLink}} and the {{#crossLink "Ticker/tick:event"}}{{/crossLink}} - * event object's "delta" properties to make this easier. - * - * Falls back on {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}} if the requestAnimationFrame API is not - * supported. - * @property RAF - * @static - * @type {String} - * @default "raf" - * @readonly - **/ - Ticker.RAF = "raf"; - - /** - * In this mode, Ticker uses the setTimeout API. This provides predictable, adaptive frame timing, but does not - * provide the benefits of requestAnimationFrame (screen synch, background throttling). - * @property TIMEOUT - * @static - * @type {String} - * @default "timeout" - * @readonly - **/ - Ticker.TIMEOUT = "timeout"; - - -// static events: - /** - * Dispatched each tick. The event will be dispatched to each listener even when the Ticker has been paused using - * {{#crossLink "Ticker/setPaused"}}{{/crossLink}}. - * - *

Example

- * - * createjs.Ticker.addEventListener("tick", handleTick); - * function handleTick(event) { - * console.log("Paused:", event.paused, event.delta); - * } - * - * @event tick - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Boolean} paused Indicates whether the ticker is currently paused. - * @param {Number} delta The time elapsed in ms since the last tick. - * @param {Number} time The total time in ms since Ticker was initialized. - * @param {Number} runTime The total time in ms that Ticker was not paused since it was initialized. For example, - * you could determine the amount of time that the Ticker has been paused since initialization with `time-runTime`. - * @since 0.6.0 - */ - - -// public static properties: - /** - * Deprecated in favour of {{#crossLink "Ticker/timingMode"}}{{/crossLink}}, and will be removed in a future version. If true, timingMode will - * use {{#crossLink "Ticker/RAF_SYNCHED"}}{{/crossLink}} by default. - * @deprecated Deprecated in favour of {{#crossLink "Ticker/timingMode"}}{{/crossLink}}. - * @property useRAF - * @static - * @type {Boolean} - * @default false - **/ - Ticker.useRAF = false; - - /** - * Specifies the timing api (setTimeout or requestAnimationFrame) and mode to use. See - * {{#crossLink "Ticker/TIMEOUT"}}{{/crossLink}}, {{#crossLink "Ticker/RAF"}}{{/crossLink}}, and - * {{#crossLink "Ticker/RAF_SYNCHED"}}{{/crossLink}} for mode details. - * @property timingMode - * @static - * @type {String} - * @default Ticker.TIMEOUT - **/ - Ticker.timingMode = null; - - /** - * Specifies a maximum value for the delta property in the tick event object. This is useful when building time - * based animations and systems to prevent issues caused by large time gaps caused by background tabs, system sleep, - * alert dialogs, or other blocking routines. Double the expected frame duration is often an effective value - * (ex. maxDelta=50 when running at 40fps). - * - * This does not impact any other values (ex. time, runTime, etc), so you may experience issues if you enable maxDelta - * when using both delta and other values. - * - * If 0, there is no maximum. - * @property maxDelta - * @static - * @type {number} - * @default 0 - */ - Ticker.maxDelta = 0; - - /** - * When the ticker is paused, all listeners will still receive a tick event, but the paused property - * of the event will be `true`. Also, while paused the `runTime` will not increase. See {{#crossLink "Ticker/tick:event"}}{{/crossLink}}, - * {{#crossLink "Ticker/getTime"}}{{/crossLink}}, and {{#crossLink "Ticker/getEventTime"}}{{/crossLink}} for more - * info. - * - *

Example

- * - * createjs.Ticker.addEventListener("tick", handleTick); - * createjs.Ticker.paused = true; - * function handleTick(event) { - * console.log(event.paused, - * createjs.Ticker.getTime(false), - * createjs.Ticker.getTime(true)); - * } - * - * @property paused - * @static - * @type {Boolean} - * @default false - **/ - Ticker.paused = false; - - -// mix-ins: - // EventDispatcher methods: - Ticker.removeEventListener = null; - Ticker.removeAllEventListeners = null; - Ticker.dispatchEvent = null; - Ticker.hasEventListener = null; - Ticker._listeners = null; - createjs.EventDispatcher.initialize(Ticker); // inject EventDispatcher methods. - Ticker._addEventListener = Ticker.addEventListener; - Ticker.addEventListener = function() { - !Ticker._inited&&Ticker.init(); - return Ticker._addEventListener.apply(Ticker, arguments); - }; - - -// private static properties: - /** - * @property _inited - * @static - * @type {Boolean} - * @protected - **/ - Ticker._inited = false; - - /** - * @property _startTime - * @static - * @type {Number} - * @protected - **/ - Ticker._startTime = 0; - - /** - * @property _pausedTime - * @static - * @type {Number} - * @protected - **/ - Ticker._pausedTime=0; - - /** - * The number of ticks that have passed - * @property _ticks - * @static - * @type {Number} - * @protected - **/ - Ticker._ticks = 0; - - /** - * The number of ticks that have passed while Ticker has been paused - * @property _pausedTicks - * @static - * @type {Number} - * @protected - **/ - Ticker._pausedTicks = 0; - - /** - * @property _interval - * @static - * @type {Number} - * @protected - **/ - Ticker._interval = 50; - - /** - * @property _lastTime - * @static - * @type {Number} - * @protected - **/ - Ticker._lastTime = 0; - - /** - * @property _times - * @static - * @type {Array} - * @protected - **/ - Ticker._times = null; - - /** - * @property _tickTimes - * @static - * @type {Array} - * @protected - **/ - Ticker._tickTimes = null; - - /** - * Stores the timeout or requestAnimationFrame id. - * @property _timerId - * @static - * @type {Number} - * @protected - **/ - Ticker._timerId = null; - - /** - * True if currently using requestAnimationFrame, false if using setTimeout. This may be different than timingMode - * if that property changed and a tick hasn't fired. - * @property _raf - * @static - * @type {Boolean} - * @protected - **/ - Ticker._raf = true; - - -// static getter / setters: - /** - * Use the {{#crossLink "Ticker/interval:property"}}{{/crossLink}} property instead. - * @method setInterval - * @static - * @param {Number} interval - * @deprecated - **/ - Ticker.setInterval = function(interval) { - Ticker._interval = interval; - if (!Ticker._inited) { return; } - Ticker._setupTick(); - }; - - /** - * Use the {{#crossLink "Ticker/interval:property"}}{{/crossLink}} property instead. - * @method getInterval - * @static - * @return {Number} - * @deprecated - **/ - Ticker.getInterval = function() { - return Ticker._interval; - }; - - /** - * Use the {{#crossLink "Ticker/framerate:property"}}{{/crossLink}} property instead. - * @method setFPS - * @static - * @param {Number} value - * @deprecated - **/ - Ticker.setFPS = function(value) { - Ticker.setInterval(1000/value); - }; - - /** - * Use the {{#crossLink "Ticker/framerate:property"}}{{/crossLink}} property instead. - * @method getFPS - * @static - * @return {Number} - * @deprecated - **/ - Ticker.getFPS = function() { - return 1000/Ticker._interval; - }; - - /** - * Indicates the target time (in milliseconds) between ticks. Default is 50 (20 FPS). - * Note that actual time between ticks may be more than specified depending on CPU load. - * This property is ignored if the ticker is using the `RAF` timing mode. - * @property interval - * @static - * @type {Number} - **/ - - /** - * Indicates the target frame rate in frames per second (FPS). Effectively just a shortcut to `interval`, where - * `framerate == 1000/interval`. - * @property framerate - * @static - * @type {Number} - **/ - try { - Object.defineProperties(Ticker, { - interval: { get: Ticker.getInterval, set: Ticker.setInterval }, - framerate: { get: Ticker.getFPS, set: Ticker.setFPS } - }); - } catch (e) { console.log(e); } - - -// public static methods: - /** - * Starts the tick. This is called automatically when the first listener is added. - * @method init - * @static - **/ - Ticker.init = function() { - if (Ticker._inited) { return; } - Ticker._inited = true; - Ticker._times = []; - Ticker._tickTimes = []; - Ticker._startTime = Ticker._getTime(); - Ticker._times.push(Ticker._lastTime = 0); - Ticker.interval = Ticker._interval; - }; - - /** - * Stops the Ticker and removes all listeners. Use init() to restart the Ticker. - * @method reset - * @static - **/ - Ticker.reset = function() { - if (Ticker._raf) { - var f = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame; - f&&f(Ticker._timerId); - } else { - clearTimeout(Ticker._timerId); - } - Ticker.removeAllEventListeners("tick"); - Ticker._timerId = Ticker._times = Ticker._tickTimes = null; - Ticker._startTime = Ticker._lastTime = Ticker._ticks = 0; - Ticker._inited = false; - }; - - /** - * Returns the average time spent within a tick. This can vary significantly from the value provided by getMeasuredFPS - * because it only measures the time spent within the tick execution stack. - * - * Example 1: With a target FPS of 20, getMeasuredFPS() returns 20fps, which indicates an average of 50ms between - * the end of one tick and the end of the next. However, getMeasuredTickTime() returns 15ms. This indicates that - * there may be up to 35ms of "idle" time between the end of one tick and the start of the next. - * - * Example 2: With a target FPS of 30, getFPS() returns 10fps, which indicates an average of 100ms between the end of - * one tick and the end of the next. However, getMeasuredTickTime() returns 20ms. This would indicate that something - * other than the tick is using ~80ms (another script, DOM rendering, etc). - * @method getMeasuredTickTime - * @static - * @param {Number} [ticks] The number of previous ticks over which to measure the average time spent in a tick. - * Defaults to the number of ticks per second. To get only the last tick's time, pass in 1. - * @return {Number} The average time spent in a tick in milliseconds. - **/ - Ticker.getMeasuredTickTime = function(ticks) { - var ttl=0, times=Ticker._tickTimes; - if (!times || times.length < 1) { return -1; } - - // by default, calculate average for the past ~1 second: - ticks = Math.min(times.length, ticks||(Ticker.getFPS()|0)); - for (var i=0; i= (Ticker._interval-1)*0.97) { - Ticker._tick(); - } - }; - - /** - * @method _handleRAF - * @static - * @protected - **/ - Ticker._handleRAF = function() { - Ticker._timerId = null; - Ticker._setupTick(); - Ticker._tick(); - }; - - /** - * @method _handleTimeout - * @static - * @protected - **/ - Ticker._handleTimeout = function() { - Ticker._timerId = null; - Ticker._setupTick(); - Ticker._tick(); - }; - - /** - * @method _setupTick - * @static - * @protected - **/ - Ticker._setupTick = function() { - if (Ticker._timerId != null) { return; } // avoid duplicates - - var mode = Ticker.timingMode||(Ticker.useRAF&&Ticker.RAF_SYNCHED); - if (mode == Ticker.RAF_SYNCHED || mode == Ticker.RAF) { - var f = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame; - if (f) { - Ticker._timerId = f(mode == Ticker.RAF ? Ticker._handleRAF : Ticker._handleSynch); - Ticker._raf = true; - return; - } - } - Ticker._raf = false; - Ticker._timerId = setTimeout(Ticker._handleTimeout, Ticker._interval); - }; - - /** - * @method _tick - * @static - * @protected - **/ - Ticker._tick = function() { - var paused = Ticker.paused; - var time = Ticker._getTime(); - var elapsedTime = time-Ticker._lastTime; - Ticker._lastTime = time; - Ticker._ticks++; - - if (paused) { - Ticker._pausedTicks++; - Ticker._pausedTime += elapsedTime; - } - - if (Ticker.hasEventListener("tick")) { - var event = new createjs.Event("tick"); - var maxDelta = Ticker.maxDelta; - event.delta = (maxDelta && elapsedTime > maxDelta) ? maxDelta : elapsedTime; - event.paused = paused; - event.time = time; - event.runTime = time-Ticker._pausedTime; - Ticker.dispatchEvent(event); - } - - Ticker._tickTimes.unshift(Ticker._getTime()-time); - while (Ticker._tickTimes.length > 100) { Ticker._tickTimes.pop(); } - - Ticker._times.unshift(time); - while (Ticker._times.length > 100) { Ticker._times.pop(); } - }; - - /** - * @method _getTime - * @static - * @protected - **/ - var now = window.performance && (performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow); - Ticker._getTime = function() { - return ((now&&now.call(performance))||(new Date().getTime())) - Ticker._startTime; - }; - - - createjs.Ticker = Ticker; -}()); - -//############################################################################## -// UID.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Global utility for generating sequential unique ID numbers. The UID class uses a static interface (ex. UID.get()) - * and should not be instantiated. - * @class UID - * @static - **/ - function UID() { - throw "UID cannot be instantiated"; - } - - -// private static properties: - /** - * @property _nextID - * @type Number - * @protected - **/ - UID._nextID = 0; - - -// public static methods: - /** - * Returns the next unique id. - * @method get - * @return {Number} The next unique id - * @static - **/ - UID.get = function() { - return UID._nextID++; - }; - - - createjs.UID = UID; -}()); - -//############################################################################## -// MouseEvent.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Passed as the parameter to all mouse/pointer/touch related events. For a listing of mouse events and their properties, - * see the {{#crossLink "DisplayObject"}}{{/crossLink}} and {{#crossLink "Stage"}}{{/crossLink}} event listings. - * @class MouseEvent - * @param {String} type The event type. - * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. - * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. - * @param {Number} stageX The normalized x position relative to the stage. - * @param {Number} stageY The normalized y position relative to the stage. - * @param {MouseEvent} nativeEvent The native DOM event related to this mouse event. - * @param {Number} pointerID The unique id for the pointer. - * @param {Boolean} primary Indicates whether this is the primary pointer in a multitouch environment. - * @param {Number} rawX The raw x position relative to the stage. - * @param {Number} rawY The raw y position relative to the stage. - * @param {DisplayObject} relatedTarget The secondary target for the event. - * @extends Event - * @constructor - **/ - function MouseEvent(type, bubbles, cancelable, stageX, stageY, nativeEvent, pointerID, primary, rawX, rawY, relatedTarget) { - this.Event_constructor(type, bubbles, cancelable); - - - // public properties: - /** - * The normalized x position on the stage. This will always be within the range 0 to stage width. - * @property stageX - * @type Number - */ - this.stageX = stageX; - - /** - * The normalized y position on the stage. This will always be within the range 0 to stage height. - * @property stageY - * @type Number - **/ - this.stageY = stageY; - - /** - * The raw x position relative to the stage. Normally this will be the same as the stageX value, unless - * stage.mouseMoveOutside is true and the pointer is outside of the stage bounds. - * @property rawX - * @type Number - */ - this.rawX = (rawX==null)?stageX:rawX; - - /** - * The raw y position relative to the stage. Normally this will be the same as the stageY value, unless - * stage.mouseMoveOutside is true and the pointer is outside of the stage bounds. - * @property rawY - * @type Number - */ - this.rawY = (rawY==null)?stageY:rawY; - - /** - * The native MouseEvent generated by the browser. The properties and API for this - * event may differ between browsers. This property will be null if the - * EaselJS property was not directly generated from a native MouseEvent. - * @property nativeEvent - * @type HtmlMouseEvent - * @default null - **/ - this.nativeEvent = nativeEvent; - - /** - * The unique id for the pointer (touch point or cursor). This will be either -1 for the mouse, or the system - * supplied id value. - * @property pointerID - * @type {Number} - */ - this.pointerID = pointerID; - - /** - * Indicates whether this is the primary pointer in a multitouch environment. This will always be true for the mouse. - * For touch pointers, the first pointer in the current stack will be considered the primary pointer. - * @property primary - * @type {Boolean} - */ - this.primary = !!primary; - - /** - * The secondary target for the event, if applicable. This is used for mouseout/rollout - * events to indicate the object that the mouse entered from, mouseover/rollover for the object the mouse exited, - * and stagemousedown/stagemouseup events for the object that was the under the cursor, if any. - * - * Only valid interaction targets will be returned (ie. objects with mouse listeners or a cursor set). - * @property relatedTarget - * @type {DisplayObject} - */ - this.relatedTarget = relatedTarget; - } - var p = createjs.extend(MouseEvent, createjs.Event); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// getter / setters: - /** - * Returns the x position of the mouse in the local coordinate system of the current target (ie. the dispatcher). - * @property localX - * @type {Number} - * @readonly - */ - p._get_localX = function() { - return this.currentTarget.globalToLocal(this.rawX, this.rawY).x; - }; - - /** - * Returns the y position of the mouse in the local coordinate system of the current target (ie. the dispatcher). - * @property localY - * @type {Number} - * @readonly - */ - p._get_localY = function() { - return this.currentTarget.globalToLocal(this.rawX, this.rawY).y; - }; - - /** - * Indicates whether the event was generated by a touch input (versus a mouse input). - * @property isTouch - * @type {Boolean} - * @readonly - */ - p._get_isTouch = function() { - return this.pointerID !== -1; - }; - - - try { - Object.defineProperties(p, { - localX: { get: p._get_localX }, - localY: { get: p._get_localY }, - isTouch: { get: p._get_isTouch } - }); - } catch (e) {} // TODO: use Log - - -// public methods: - /** - * Returns a clone of the MouseEvent instance. - * @method clone - * @return {MouseEvent} a clone of the MouseEvent instance. - **/ - p.clone = function() { - return new MouseEvent(this.type, this.bubbles, this.cancelable, this.stageX, this.stageY, this.nativeEvent, this.pointerID, this.primary, this.rawX, this.rawY); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[MouseEvent (type="+this.type+" stageX="+this.stageX+" stageY="+this.stageY+")]"; - }; - - - createjs.MouseEvent = createjs.promote(MouseEvent, "Event"); -}()); - -//############################################################################## -// Matrix2D.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Represents an affine transformation matrix, and provides tools for constructing and concatenating matrices. - * - * This matrix can be visualized as: - * - * [ a c tx - * b d ty - * 0 0 1 ] - * - * Note the locations of b and c. - * - * @class Matrix2D - * @param {Number} [a=1] Specifies the a property for the new matrix. - * @param {Number} [b=0] Specifies the b property for the new matrix. - * @param {Number} [c=0] Specifies the c property for the new matrix. - * @param {Number} [d=1] Specifies the d property for the new matrix. - * @param {Number} [tx=0] Specifies the tx property for the new matrix. - * @param {Number} [ty=0] Specifies the ty property for the new matrix. - * @constructor - **/ - function Matrix2D(a, b, c, d, tx, ty) { - this.setValues(a,b,c,d,tx,ty); - - // public properties: - // assigned in the setValues method. - /** - * Position (0, 0) in a 3x3 affine transformation matrix. - * @property a - * @type Number - **/ - - /** - * Position (0, 1) in a 3x3 affine transformation matrix. - * @property b - * @type Number - **/ - - /** - * Position (1, 0) in a 3x3 affine transformation matrix. - * @property c - * @type Number - **/ - - /** - * Position (1, 1) in a 3x3 affine transformation matrix. - * @property d - * @type Number - **/ - - /** - * Position (2, 0) in a 3x3 affine transformation matrix. - * @property tx - * @type Number - **/ - - /** - * Position (2, 1) in a 3x3 affine transformation matrix. - * @property ty - * @type Number - **/ - } - var p = Matrix2D.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// constants: - /** - * Multiplier for converting degrees to radians. Used internally by Matrix2D. - * @property DEG_TO_RAD - * @static - * @final - * @type Number - * @readonly - **/ - Matrix2D.DEG_TO_RAD = Math.PI/180; - - -// static public properties: - /** - * An identity matrix, representing a null transformation. - * @property identity - * @static - * @type Matrix2D - * @readonly - **/ - Matrix2D.identity = null; // set at bottom of class definition. - - -// public methods: - /** - * Sets the specified values on this instance. - * @method setValues - * @param {Number} [a=1] Specifies the a property for the new matrix. - * @param {Number} [b=0] Specifies the b property for the new matrix. - * @param {Number} [c=0] Specifies the c property for the new matrix. - * @param {Number} [d=1] Specifies the d property for the new matrix. - * @param {Number} [tx=0] Specifies the tx property for the new matrix. - * @param {Number} [ty=0] Specifies the ty property for the new matrix. - * @return {Matrix2D} This instance. Useful for chaining method calls. - */ - p.setValues = function(a, b, c, d, tx, ty) { - // don't forget to update docs in the constructor if these change: - this.a = (a == null) ? 1 : a; - this.b = b || 0; - this.c = c || 0; - this.d = (d == null) ? 1 : d; - this.tx = tx || 0; - this.ty = ty || 0; - return this; - }; - - /** - * Appends the specified matrix properties to this matrix. All parameters are required. - * This is the equivalent of multiplying `(this matrix) * (specified matrix)`. - * @method append - * @param {Number} a - * @param {Number} b - * @param {Number} c - * @param {Number} d - * @param {Number} tx - * @param {Number} ty - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.append = function(a, b, c, d, tx, ty) { - var a1 = this.a; - var b1 = this.b; - var c1 = this.c; - var d1 = this.d; - if (a != 1 || b != 0 || c != 0 || d != 1) { - this.a = a1*a+c1*b; - this.b = b1*a+d1*b; - this.c = a1*c+c1*d; - this.d = b1*c+d1*d; - } - this.tx = a1*tx+c1*ty+this.tx; - this.ty = b1*tx+d1*ty+this.ty; - return this; - }; - - /** - * Prepends the specified matrix properties to this matrix. - * This is the equivalent of multiplying `(specified matrix) * (this matrix)`. - * All parameters are required. - * @method prepend - * @param {Number} a - * @param {Number} b - * @param {Number} c - * @param {Number} d - * @param {Number} tx - * @param {Number} ty - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.prepend = function(a, b, c, d, tx, ty) { - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a*a1+c*this.b; - this.b = b*a1+d*this.b; - this.c = a*c1+c*this.d; - this.d = b*c1+d*this.d; - this.tx = a*tx1+c*this.ty+tx; - this.ty = b*tx1+d*this.ty+ty; - return this; - }; - - /** - * Appends the specified matrix to this matrix. - * This is the equivalent of multiplying `(this matrix) * (specified matrix)`. - * @method appendMatrix - * @param {Matrix2D} matrix - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.appendMatrix = function(matrix) { - return this.append(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); - }; - - /** - * Prepends the specified matrix to this matrix. - * This is the equivalent of multiplying `(specified matrix) * (this matrix)`. - * For example, you could calculate the combined transformation for a child object using: - * - * var o = myDisplayObject; - * var mtx = o.getMatrix(); - * while (o = o.parent) { - * // prepend each parent's transformation in turn: - * o.prependMatrix(o.getMatrix()); - * } - * @method prependMatrix - * @param {Matrix2D} matrix - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.prependMatrix = function(matrix) { - return this.prepend(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); - }; - - /** - * Generates matrix properties from the specified display object transform properties, and appends them to this matrix. - * For example, you can use this to generate a matrix representing the transformations of a display object: - * - * var mtx = new createjs.Matrix2D(); - * mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation); - * @method appendTransform - * @param {Number} x - * @param {Number} y - * @param {Number} scaleX - * @param {Number} scaleY - * @param {Number} rotation - * @param {Number} skewX - * @param {Number} skewY - * @param {Number} regX Optional. - * @param {Number} regY Optional. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.appendTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) { - if (rotation%360) { - var r = rotation*Matrix2D.DEG_TO_RAD; - var cos = Math.cos(r); - var sin = Math.sin(r); - } else { - cos = 1; - sin = 0; - } - - if (skewX || skewY) { - // TODO: can this be combined into a single append operation? - skewX *= Matrix2D.DEG_TO_RAD; - skewY *= Matrix2D.DEG_TO_RAD; - this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y); - this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0); - } else { - this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y); - } - - if (regX || regY) { - // append the registration offset: - this.tx -= regX*this.a+regY*this.c; - this.ty -= regX*this.b+regY*this.d; - } - return this; - }; - - /** - * Generates matrix properties from the specified display object transform properties, and prepends them to this matrix. - * For example, you could calculate the combined transformation for a child object using: - * - * var o = myDisplayObject; - * var mtx = new createjs.Matrix2D(); - * do { - * // prepend each parent's transformation in turn: - * mtx.prependTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY); - * } while (o = o.parent); - * - * Note that the above example would not account for {{#crossLink "DisplayObject/transformMatrix:property"}}{{/crossLink}} - * values. See {{#crossLink "Matrix2D/prependMatrix"}}{{/crossLink}} for an example that does. - * @method prependTransform - * @param {Number} x - * @param {Number} y - * @param {Number} scaleX - * @param {Number} scaleY - * @param {Number} rotation - * @param {Number} skewX - * @param {Number} skewY - * @param {Number} regX Optional. - * @param {Number} regY Optional. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.prependTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) { - if (rotation%360) { - var r = rotation*Matrix2D.DEG_TO_RAD; - var cos = Math.cos(r); - var sin = Math.sin(r); - } else { - cos = 1; - sin = 0; - } - - if (regX || regY) { - // prepend the registration offset: - this.tx -= regX; this.ty -= regY; - } - if (skewX || skewY) { - // TODO: can this be combined into a single prepend operation? - skewX *= Matrix2D.DEG_TO_RAD; - skewY *= Matrix2D.DEG_TO_RAD; - this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0); - this.prepend(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y); - } else { - this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y); - } - return this; - }; - - /** - * Applies a clockwise rotation transformation to the matrix. - * @method rotate - * @param {Number} angle The angle to rotate by, in degrees. To use a value in radians, multiply it by `180/Math.PI`. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.rotate = function(angle) { - angle = angle*Matrix2D.DEG_TO_RAD; - var cos = Math.cos(angle); - var sin = Math.sin(angle); - - var a1 = this.a; - var b1 = this.b; - - this.a = a1*cos+this.c*sin; - this.b = b1*cos+this.d*sin; - this.c = -a1*sin+this.c*cos; - this.d = -b1*sin+this.d*cos; - return this; - }; - - /** - * Applies a skew transformation to the matrix. - * @method skew - * @param {Number} skewX The amount to skew horizontally in degrees. To use a value in radians, multiply it by `180/Math.PI`. - * @param {Number} skewY The amount to skew vertically in degrees. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - */ - p.skew = function(skewX, skewY) { - skewX = skewX*Matrix2D.DEG_TO_RAD; - skewY = skewY*Matrix2D.DEG_TO_RAD; - this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), 0, 0); - return this; - }; - - /** - * Applies a scale transformation to the matrix. - * @method scale - * @param {Number} x The amount to scale horizontally. E.G. a value of 2 will double the size in the X direction, and 0.5 will halve it. - * @param {Number} y The amount to scale vertically. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.scale = function(x, y) { - this.a *= x; - this.b *= x; - this.c *= y; - this.d *= y; - //this.tx *= x; - //this.ty *= y; - return this; - }; - - /** - * Translates the matrix on the x and y axes. - * @method translate - * @param {Number} x - * @param {Number} y - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.translate = function(x, y) { - this.tx += this.a*x + this.c*y; - this.ty += this.b*x + this.d*y; - return this; - }; - - /** - * Sets the properties of the matrix to those of an identity matrix (one that applies a null transformation). - * @method identity - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.identity = function() { - this.a = this.d = 1; - this.b = this.c = this.tx = this.ty = 0; - return this; - }; - - /** - * Inverts the matrix, causing it to perform the opposite transformation. - * @method invert - * @return {Matrix2D} This matrix. Useful for chaining method calls. - **/ - p.invert = function() { - var a1 = this.a; - var b1 = this.b; - var c1 = this.c; - var d1 = this.d; - var tx1 = this.tx; - var n = a1*d1-b1*c1; - - this.a = d1/n; - this.b = -b1/n; - this.c = -c1/n; - this.d = a1/n; - this.tx = (c1*this.ty-d1*tx1)/n; - this.ty = -(a1*this.ty-b1*tx1)/n; - return this; - }; - - /** - * Returns true if the matrix is an identity matrix. - * @method isIdentity - * @return {Boolean} - **/ - p.isIdentity = function() { - return this.tx === 0 && this.ty === 0 && this.a === 1 && this.b === 0 && this.c === 0 && this.d === 1; - }; - - /** - * Returns true if this matrix is equal to the specified matrix (all property values are equal). - * @method equals - * @param {Matrix2D} matrix The matrix to compare. - * @return {Boolean} - **/ - p.equals = function(matrix) { - return this.tx === matrix.tx && this.ty === matrix.ty && this.a === matrix.a && this.b === matrix.b && this.c === matrix.c && this.d === matrix.d; - }; - - /** - * Transforms a point according to this matrix. - * @method transformPoint - * @param {Number} x The x component of the point to transform. - * @param {Number} y The y component of the point to transform. - * @param {Point | Object} [pt] An object to copy the result into. If omitted a generic object with x/y properties will be returned. - * @return {Point} This matrix. Useful for chaining method calls. - **/ - p.transformPoint = function(x, y, pt) { - pt = pt||{}; - pt.x = x*this.a+y*this.c+this.tx; - pt.y = x*this.b+y*this.d+this.ty; - return pt; - }; - - /** - * Decomposes the matrix into transform properties (x, y, scaleX, scaleY, and rotation). Note that these values - * may not match the transform properties you used to generate the matrix, though they will produce the same visual - * results. - * @method decompose - * @param {Object} target The object to apply the transform properties to. If null, then a new object will be returned. - * @return {Object} The target, or a new generic object with the transform properties applied. - */ - p.decompose = function(target) { - // TODO: it would be nice to be able to solve for whether the matrix can be decomposed into only scale/rotation even when scale is negative - if (target == null) { target = {}; } - target.x = this.tx; - target.y = this.ty; - target.scaleX = Math.sqrt(this.a * this.a + this.b * this.b); - target.scaleY = Math.sqrt(this.c * this.c + this.d * this.d); - - var skewX = Math.atan2(-this.c, this.d); - var skewY = Math.atan2(this.b, this.a); - - var delta = Math.abs(1-skewX/skewY); - if (delta < 0.00001) { // effectively identical, can use rotation: - target.rotation = skewY/Matrix2D.DEG_TO_RAD; - if (this.a < 0 && this.d >= 0) { - target.rotation += (target.rotation <= 0) ? 180 : -180; - } - target.skewX = target.skewY = 0; - } else { - target.skewX = skewX/Matrix2D.DEG_TO_RAD; - target.skewY = skewY/Matrix2D.DEG_TO_RAD; - } - return target; - }; - - /** - * Copies all properties from the specified matrix to this matrix. - * @method copy - * @param {Matrix2D} matrix The matrix to copy properties from. - * @return {Matrix2D} This matrix. Useful for chaining method calls. - */ - p.copy = function(matrix) { - return this.setValues(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty); - }; - - /** - * Returns a clone of the Matrix2D instance. - * @method clone - * @return {Matrix2D} a clone of the Matrix2D instance. - **/ - p.clone = function() { - return new Matrix2D(this.a, this.b, this.c, this.d, this.tx, this.ty); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Matrix2D (a="+this.a+" b="+this.b+" c="+this.c+" d="+this.d+" tx="+this.tx+" ty="+this.ty+")]"; - }; - - // this has to be populated after the class is defined: - Matrix2D.identity = new Matrix2D(); - - - createjs.Matrix2D = Matrix2D; -}()); - -//############################################################################## -// DisplayProps.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - /** - * Used for calculating and encapsulating display related properties. - * @class DisplayProps - * @param {Number} [visible=true] Visible value. - * @param {Number} [alpha=1] Alpha value. - * @param {Number} [shadow=null] A Shadow instance or null. - * @param {Number} [compositeOperation=null] A compositeOperation value or null. - * @param {Number} [matrix] A transformation matrix. Defaults to a new identity matrix. - * @constructor - **/ - function DisplayProps(visible, alpha, shadow, compositeOperation, matrix) { - this.setValues(visible, alpha, shadow, compositeOperation, matrix); - - // public properties: - // assigned in the setValues method. - /** - * Property representing the alpha that will be applied to a display object. - * @property alpha - * @type Number - **/ - - /** - * Property representing the shadow that will be applied to a display object. - * @property shadow - * @type Shadow - **/ - - /** - * Property representing the compositeOperation that will be applied to a display object. - * You can find a list of valid composite operations at: - * https://developer.mozilla.org/en/Canvas_tutorial/Compositing - * @property compositeOperation - * @type String - **/ - - /** - * Property representing the value for visible that will be applied to a display object. - * @property visible - * @type Boolean - **/ - - /** - * The transformation matrix that will be applied to a display object. - * @property matrix - * @type Matrix2D - **/ - } - var p = DisplayProps.prototype; - -// initialization: - /** - * Reinitializes the instance with the specified values. - * @method setValues - * @param {Number} [visible=true] Visible value. - * @param {Number} [alpha=1] Alpha value. - * @param {Number} [shadow=null] A Shadow instance or null. - * @param {Number} [compositeOperation=null] A compositeOperation value or null. - * @param {Number} [matrix] A transformation matrix. Defaults to an identity matrix. - * @return {DisplayProps} This instance. Useful for chaining method calls. - * @chainable - */ - p.setValues = function (visible, alpha, shadow, compositeOperation, matrix) { - this.visible = visible == null ? true : !!visible; - this.alpha = alpha == null ? 1 : alpha; - this.shadow = shadow; - this.compositeOperation = compositeOperation; - this.matrix = matrix || (this.matrix&&this.matrix.identity()) || new createjs.Matrix2D(); - return this; - }; - -// public methods: - /** - * Appends the specified display properties. This is generally used to apply a child's properties its parent's. - * @method append - * @param {Boolean} visible desired visible value - * @param {Number} alpha desired alpha value - * @param {Shadow} shadow desired shadow value - * @param {String} compositeOperation desired composite operation value - * @param {Matrix2D} [matrix] a Matrix2D instance - * @return {DisplayProps} This instance. Useful for chaining method calls. - * @chainable - */ - p.append = function(visible, alpha, shadow, compositeOperation, matrix) { - this.alpha *= alpha; - this.shadow = shadow || this.shadow; - this.compositeOperation = compositeOperation || this.compositeOperation; - this.visible = this.visible && visible; - matrix&&this.matrix.appendMatrix(matrix); - return this; - }; - - /** - * Prepends the specified display properties. This is generally used to apply a parent's properties to a child's. - * For example, to get the combined display properties that would be applied to a child, you could use: - * - * var o = myDisplayObject; - * var props = new createjs.DisplayProps(); - * do { - * // prepend each parent's props in turn: - * props.prepend(o.visible, o.alpha, o.shadow, o.compositeOperation, o.getMatrix()); - * } while (o = o.parent); - * - * @method prepend - * @param {Boolean} visible desired visible value - * @param {Number} alpha desired alpha value - * @param {Shadow} shadow desired shadow value - * @param {String} compositeOperation desired composite operation value - * @param {Matrix2D} [matrix] a Matrix2D instance - * @return {DisplayProps} This instance. Useful for chaining method calls. - * @chainable - */ - p.prepend = function(visible, alpha, shadow, compositeOperation, matrix) { - this.alpha *= alpha; - this.shadow = this.shadow || shadow; - this.compositeOperation = this.compositeOperation || compositeOperation; - this.visible = this.visible && visible; - matrix&&this.matrix.prependMatrix(matrix); - return this; - }; - - /** - * Resets this instance and its matrix to default values. - * @method identity - * @return {DisplayProps} This instance. Useful for chaining method calls. - * @chainable - */ - p.identity = function() { - this.visible = true; - this.alpha = 1; - this.shadow = this.compositeOperation = null; - this.matrix.identity(); - return this; - }; - - /** - * Returns a clone of the DisplayProps instance. Clones the associated matrix. - * @method clone - * @return {DisplayProps} a clone of the DisplayProps instance. - **/ - p.clone = function() { - return new DisplayProps(this.alpha, this.shadow, this.compositeOperation, this.visible, this.matrix.clone()); - }; - -// private methods: - - createjs.DisplayProps = DisplayProps; -})(); - -//############################################################################## -// Point.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Represents a point on a 2 dimensional x / y coordinate system. - * - *

Example

- * - * var point = new createjs.Point(0, 100); - * - * @class Point - * @param {Number} [x=0] X position. - * @param {Number} [y=0] Y position. - * @constructor - **/ - function Point(x, y) { - this.setValues(x, y); - - - // public properties: - // assigned in the setValues method. - /** - * X position. - * @property x - * @type Number - **/ - - /** - * Y position. - * @property y - * @type Number - **/ - } - var p = Point.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// public methods: - /** - * Sets the specified values on this instance. - * @method setValues - * @param {Number} [x=0] X position. - * @param {Number} [y=0] Y position. - * @return {Point} This instance. Useful for chaining method calls. - * @chainable - */ - p.setValues = function(x, y) { - this.x = x||0; - this.y = y||0; - return this; - }; - - /** - * Copies all properties from the specified point to this point. - * @method copy - * @param {Point} point The point to copy properties from. - * @return {Point} This point. Useful for chaining method calls. - * @chainable - */ - p.copy = function(point) { - this.x = point.x; - this.y = point.y; - return this; - }; - - /** - * Returns a clone of the Point instance. - * @method clone - * @return {Point} a clone of the Point instance. - **/ - p.clone = function() { - return new Point(this.x, this.y); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Point (x="+this.x+" y="+this.y+")]"; - }; - - - createjs.Point = Point; -}()); - -//############################################################################## -// Rectangle.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Represents a rectangle as defined by the points (x, y) and (x+width, y+height). - * - *

Example

- * - * var rect = new createjs.Rectangle(0, 0, 100, 100); - * - * @class Rectangle - * @param {Number} [x=0] X position. - * @param {Number} [y=0] Y position. - * @param {Number} [width=0] The width of the Rectangle. - * @param {Number} [height=0] The height of the Rectangle. - * @constructor - **/ - function Rectangle(x, y, width, height) { - this.setValues(x, y, width, height); - - - // public properties: - // assigned in the setValues method. - /** - * X position. - * @property x - * @type Number - **/ - - /** - * Y position. - * @property y - * @type Number - **/ - - /** - * Width. - * @property width - * @type Number - **/ - - /** - * Height. - * @property height - * @type Number - **/ - } - var p = Rectangle.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// public methods: - /** - * Sets the specified values on this instance. - * @method setValues - * @param {Number} [x=0] X position. - * @param {Number} [y=0] Y position. - * @param {Number} [width=0] The width of the Rectangle. - * @param {Number} [height=0] The height of the Rectangle. - * @return {Rectangle} This instance. Useful for chaining method calls. - * @chainable - */ - p.setValues = function(x, y, width, height) { - // don't forget to update docs in the constructor if these change: - this.x = x||0; - this.y = y||0; - this.width = width||0; - this.height = height||0; - return this; - }; - - /** - * Extends the rectangle's bounds to include the described point or rectangle. - * @method extend - * @param {Number} x X position of the point or rectangle. - * @param {Number} y Y position of the point or rectangle. - * @param {Number} [width=0] The width of the rectangle. - * @param {Number} [height=0] The height of the rectangle. - * @return {Rectangle} This instance. Useful for chaining method calls. - * @chainable - */ - p.extend = function(x, y, width, height) { - width = width||0; - height = height||0; - if (x+width > this.x+this.width) { this.width = x+width-this.x; } - if (y+height > this.y+this.height) { this.height = y+height-this.y; } - if (x < this.x) { this.width += this.x-x; this.x = x; } - if (y < this.y) { this.height += this.y-y; this.y = y; } - return this; - }; - - /** - * Adds the specified padding to the rectangle's bounds. - * @method pad - * @param {Number} top - * @param {Number} left - * @param {Number} right - * @param {Number} bottom - * @return {Rectangle} This instance. Useful for chaining method calls. - * @chainable - */ - p.pad = function(top, left, bottom, right) { - this.x -= left; - this.y -= top; - this.width += left+right; - this.height += top+bottom; - return this; - }; - - /** - * Copies all properties from the specified rectangle to this rectangle. - * @method copy - * @param {Rectangle} rectangle The rectangle to copy properties from. - * @return {Rectangle} This rectangle. Useful for chaining method calls. - * @chainable - */ - p.copy = function(rectangle) { - return this.setValues(rectangle.x, rectangle.y, rectangle.width, rectangle.height); - }; - - /** - * Returns true if this rectangle fully encloses the described point or rectangle. - * @method contains - * @param {Number} x X position of the point or rectangle. - * @param {Number} y Y position of the point or rectangle. - * @param {Number} [width=0] The width of the rectangle. - * @param {Number} [height=0] The height of the rectangle. - * @return {Boolean} True if the described point or rectangle is contained within this rectangle. - */ - p.contains = function(x, y, width, height) { - width = width||0; - height = height||0; - return (x >= this.x && x+width <= this.x+this.width && y >= this.y && y+height <= this.y+this.height); - }; - - /** - * Returns a new rectangle which contains this rectangle and the specified rectangle. - * @method union - * @param {Rectangle} rect The rectangle to calculate a union with. - * @return {Rectangle} A new rectangle describing the union. - */ - p.union = function(rect) { - return this.clone().extend(rect.x, rect.y, rect.width, rect.height); - }; - - /** - * Returns a new rectangle which describes the intersection (overlap) of this rectangle and the specified rectangle, - * or null if they do not intersect. - * @method intersection - * @param {Rectangle} rect The rectangle to calculate an intersection with. - * @return {Rectangle} A new rectangle describing the intersection or null. - */ - p.intersection = function(rect) { - var x1 = rect.x, y1 = rect.y, x2 = x1+rect.width, y2 = y1+rect.height; - if (this.x > x1) { x1 = this.x; } - if (this.y > y1) { y1 = this.y; } - if (this.x + this.width < x2) { x2 = this.x + this.width; } - if (this.y + this.height < y2) { y2 = this.y + this.height; } - return (x2 <= x1 || y2 <= y1) ? null : new Rectangle(x1, y1, x2-x1, y2-y1); - }; - - /** - * Returns true if the specified rectangle intersects (has any overlap) with this rectangle. - * @method intersects - * @param {Rectangle} rect The rectangle to compare. - * @return {Boolean} True if the rectangles intersect. - */ - p.intersects = function(rect) { - return (rect.x <= this.x+this.width && this.x <= rect.x+rect.width && rect.y <= this.y+this.height && this.y <= rect.y + rect.height); - }; - - /** - * Returns true if the width or height are equal or less than 0. - * @method isEmpty - * @return {Boolean} True if the rectangle is empty. - */ - p.isEmpty = function() { - return this.width <= 0 || this.height <= 0; - }; - - /** - * Returns a clone of the Rectangle instance. - * @method clone - * @return {Rectangle} a clone of the Rectangle instance. - **/ - p.clone = function() { - return new Rectangle(this.x, this.y, this.width, this.height); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Rectangle (x="+this.x+" y="+this.y+" width="+this.width+" height="+this.height+")]"; - }; - - - createjs.Rectangle = Rectangle; -}()); - -//############################################################################## -// ButtonHelper.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * The ButtonHelper is a helper class to create interactive buttons from {{#crossLink "MovieClip"}}{{/crossLink}} or - * {{#crossLink "Sprite"}}{{/crossLink}} instances. This class will intercept mouse events from an object, and - * automatically call {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} or {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}}, - * to the respective animation labels, add a pointer cursor, and allows the user to define a hit state frame. - * - * The ButtonHelper instance does not need to be added to the stage, but a reference should be maintained to prevent - * garbage collection. - * - * Note that over states will not work unless you call {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. - * - *

Example

- * - * var helper = new createjs.ButtonHelper(myInstance, "out", "over", "down", false, myInstance, "hit"); - * myInstance.addEventListener("click", handleClick); - * function handleClick(event) { - * // Click Happened. - * } - * - * @class ButtonHelper - * @param {Sprite|MovieClip} target The instance to manage. - * @param {String} [outLabel="out"] The label or animation to go to when the user rolls out of the button. - * @param {String} [overLabel="over"] The label or animation to go to when the user rolls over the button. - * @param {String} [downLabel="down"] The label or animation to go to when the user presses the button. - * @param {Boolean} [play=false] If the helper should call "gotoAndPlay" or "gotoAndStop" on the button when changing - * states. - * @param {DisplayObject} [hitArea] An optional item to use as the hit state for the button. If this is not defined, - * then the button's visible states will be used instead. Note that the same instance as the "target" argument can be - * used for the hitState. - * @param {String} [hitLabel] The label or animation on the hitArea instance that defines the hitArea bounds. If this is - * null, then the default state of the hitArea will be used. * - * @constructor - */ - function ButtonHelper(target, outLabel, overLabel, downLabel, play, hitArea, hitLabel) { - if (!target.addEventListener) { return; } - - - // public properties: - /** - * The target for this button helper. - * @property target - * @type MovieClip | Sprite - * @readonly - **/ - this.target = target; - - /** - * The label name or frame number to display when the user mouses out of the target. Defaults to "over". - * @property overLabel - * @type String | Number - **/ - this.overLabel = overLabel == null ? "over" : overLabel; - - /** - * The label name or frame number to display when the user mouses over the target. Defaults to "out". - * @property outLabel - * @type String | Number - **/ - this.outLabel = outLabel == null ? "out" : outLabel; - - /** - * The label name or frame number to display when the user presses on the target. Defaults to "down". - * @property downLabel - * @type String | Number - **/ - this.downLabel = downLabel == null ? "down" : downLabel; - - /** - * If true, then ButtonHelper will call gotoAndPlay, if false, it will use gotoAndStop. Default is false. - * @property play - * @default false - * @type Boolean - **/ - this.play = play; - - - // private properties - /** - * @property _isPressed - * @type Boolean - * @protected - **/ - this._isPressed = false; - - /** - * @property _isOver - * @type Boolean - * @protected - **/ - this._isOver = false; - - /** - * @property _enabled - * @type Boolean - * @protected - **/ - this._enabled = false; - - // setup: - target.mouseChildren = false; // prevents issues when children are removed from the display list when state changes. - this.enabled = true; - this.handleEvent({}); - if (hitArea) { - if (hitLabel) { - hitArea.actionsEnabled = false; - hitArea.gotoAndStop&&hitArea.gotoAndStop(hitLabel); - } - target.hitArea = hitArea; - } - } - var p = ButtonHelper.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// getter / setters: - /** - * Use the {{#crossLink "ButtonHelper/enabled:property"}}{{/crossLink}} property instead. - * @method setEnabled - * @param {Boolean} value - * @deprecated - **/ - p.setEnabled = function(value) { // TODO: deprecated. - if (value == this._enabled) { return; } - var o = this.target; - this._enabled = value; - if (value) { - o.cursor = "pointer"; - o.addEventListener("rollover", this); - o.addEventListener("rollout", this); - o.addEventListener("mousedown", this); - o.addEventListener("pressup", this); - if (o._reset) { o.__reset = o._reset; o._reset = this._reset;} - } else { - o.cursor = null; - o.removeEventListener("rollover", this); - o.removeEventListener("rollout", this); - o.removeEventListener("mousedown", this); - o.removeEventListener("pressup", this); - if (o.__reset) { o._reset = o.__reset; delete(o.__reset); } - } - }; - /** - * Use the {{#crossLink "ButtonHelper/enabled:property"}}{{/crossLink}} property instead. - * @method getEnabled - * @return {Boolean} - * @deprecated - **/ - p.getEnabled = function() { - return this._enabled; - }; - - /** - * Enables or disables the button functionality on the target. - * @property enabled - * @type {Boolean} - **/ - try { - Object.defineProperties(p, { - enabled: { get: p.getEnabled, set: p.setEnabled } - }); - } catch (e) {} // TODO: use Log - - -// public methods: - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[ButtonHelper]"; - }; - - -// private methods: - /** - * @method handleEvent - * @param {Object} evt The mouse event to handle. - * @protected - **/ - p.handleEvent = function(evt) { - var label, t = this.target, type = evt.type; - if (type == "mousedown") { - this._isPressed = true; - label = this.downLabel; - } else if (type == "pressup") { - this._isPressed = false; - label = this._isOver ? this.overLabel : this.outLabel; - } else if (type == "rollover") { - this._isOver = true; - label = this._isPressed ? this.downLabel : this.overLabel; - } else { // rollout and default - this._isOver = false; - label = this._isPressed ? this.overLabel : this.outLabel; - } - if (this.play) { - t.gotoAndPlay&&t.gotoAndPlay(label); - } else { - t.gotoAndStop&&t.gotoAndStop(label); - } - }; - - /** - * Injected into target. Preserves the paused state through a reset. - * @method _reset - * @protected - **/ - p._reset = function() { - // TODO: explore better ways to handle this issue. This is hacky & disrupts object signatures. - var p = this.paused; - this.__reset(); - this.paused = p; - }; - - - createjs.ButtonHelper = ButtonHelper; -}()); - -//############################################################################## -// Shadow.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * This class encapsulates the properties required to define a shadow to apply to a {{#crossLink "DisplayObject"}}{{/crossLink}} - * via its shadow property. - * - *

Example

- * - * myImage.shadow = new createjs.Shadow("#000000", 5, 5, 10); - * - * @class Shadow - * @constructor - * @param {String} color The color of the shadow. This can be any valid CSS color value. - * @param {Number} offsetX The x offset of the shadow in pixels. - * @param {Number} offsetY The y offset of the shadow in pixels. - * @param {Number} blur The size of the blurring effect. - **/ - function Shadow(color, offsetX, offsetY, blur) { - - - // public properties: - /** - * The color of the shadow. This can be any valid CSS color value. - * @property color - * @type String - * @default null - */ - this.color = color||"black"; - - /** The x offset of the shadow. - * @property offsetX - * @type Number - * @default 0 - */ - this.offsetX = offsetX||0; - - /** The y offset of the shadow. - * @property offsetY - * @type Number - * @default 0 - */ - this.offsetY = offsetY||0; - - /** The blur of the shadow. - * @property blur - * @type Number - * @default 0 - */ - this.blur = blur||0; - } - var p = Shadow.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// static public properties: - /** - * An identity shadow object (all properties are set to 0). - * @property identity - * @type Shadow - * @static - * @final - * @readonly - **/ - Shadow.identity = new Shadow("transparent", 0, 0, 0); - - -// public methods: - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Shadow]"; - }; - - /** - * Returns a clone of this Shadow instance. - * @method clone - * @return {Shadow} A clone of the current Shadow instance. - **/ - p.clone = function() { - return new Shadow(this.color, this.offsetX, this.offsetY, this.blur); - }; - - - createjs.Shadow = Shadow; -}()); - -//############################################################################## -// SpriteSheet.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Encapsulates the properties and methods associated with a sprite sheet. A sprite sheet is a series of images (usually - * animation frames) combined into a larger image (or images). For example, an animation consisting of eight 100x100 - * images could be combined into a single 400x200 sprite sheet (4 frames across by 2 high). - * - * The data passed to the SpriteSheet constructor defines: - *
    - *
  1. The source image or images to use.
  2. - *
  3. The positions of individual image frames.
  4. - *
  5. Sequences of frames that form named animations. Optional.
  6. - *
  7. The target playback framerate. Optional.
  8. - *
- *

SpriteSheet Format

- * SpriteSheets are an object with two required properties (`images` and `frames`), and two optional properties - * (`framerate` and `animations`). This makes them easy to define in javascript code, or in JSON. - * - *

images

- * An array of source images. Images can be either an HTMlimage - * instance, or a uri to an image. The former is recommended to control preloading. - * - * images: [image1, "path/to/image2.png"], - * - *

frames

- * Defines the individual frames. There are two supported formats for frame data: - * When all of the frames are the same size (in a grid), use an object with `width`, `height`, `regX`, `regY`, - * and `count` properties. - * - *
    - *
  • `width` & `height` are required and specify the dimensions of the frames
  • - *
  • `regX` & `regY` indicate the registration point or "origin" of the frames
  • - *
  • `spacing` indicate the spacing between frames
  • - *
  • `margin` specify the margin around the image(s)
  • - *
  • `count` allows you to specify the total number of frames in the spritesheet; if omitted, this will - * be calculated based on the dimensions of the source images and the frames. Frames will be assigned - * indexes based on their position in the source images (left to right, top to bottom).
  • - *
- * - * frames: {width:64, height:64, count:20, regX: 32, regY:64, spacing:0, margin:0} - * - * If the frames are of different sizes, use an array of frame definitions. Each definition is itself an array - * with 4 required and 3 optional entries, in the order: - * - *
    - *
  • The first four, `x`, `y`, `width`, and `height` are required and define the frame rectangle.
  • - *
  • The fifth, `imageIndex`, specifies the index of the source image (defaults to 0)
  • - *
  • The last two, `regX` and `regY` specify the registration point of the frame
  • - *
- * - * frames: [ - * // x, y, width, height, imageIndex*, regX*, regY* - * [64, 0, 96, 64], - * [0, 0, 64, 64, 1, 32, 32] - * // etc. - * ] - * - *

animations

- * Optional. An object defining sequences of frames to play as named animations. Each property corresponds to an - * animation of the same name. Each animation must specify the frames to play, and may - * also include a relative playback `speed` (ex. 2 would playback at double speed, 0.5 at half), and - * the name of the `next` animation to sequence to after it completes. - * - * There are three formats supported for defining the frames in an animation, which can be mixed and matched as appropriate: - *
    - *
  1. for a single frame animation, you can simply specify the frame index - * - * animations: { - * sit: 7 - * } - * - *
  2. - *
  3. - * for an animation of consecutive frames, you can use an array with two required, and two optional entries - * in the order: `start`, `end`, `next`, and `speed`. This will play the frames from start to end inclusive. - * - * animations: { - * // start, end, next*, speed* - * run: [0, 8], - * jump: [9, 12, "run", 2] - * } - * - *
  4. - *
  5. - * for non-consecutive frames, you can use an object with a `frames` property defining an array of frame - * indexes to play in order. The object can also specify `next` and `speed` properties. - * - * animations: { - * walk: { - * frames: [1,2,3,3,2,1] - * }, - * shoot: { - * frames: [1,4,5,6], - * next: "walk", - * speed: 0.5 - * } - * } - * - *
  6. - *
- * Note: the `speed` property was added in EaselJS 0.7.0. Earlier versions had a `frequency` - * property instead, which was the inverse of `speed`. For example, a value of "4" would be 1/4 normal speed in - * earlier versions, but is 4x normal speed in EaselJS 0.7.0+. - * - *

framerate

- * Optional. Indicates the default framerate to play this spritesheet at in frames per second. See - * {{#crossLink "SpriteSheet/framerate:property"}}{{/crossLink}} for more information. - * - * framerate: 20 - * - * Note that the Sprite framerate will only work if the stage update method is provided with the {{#crossLink "Ticker/tick:event"}}{{/crossLink}} - * event generated by the {{#crossLink "Ticker"}}{{/crossLink}}. - * - * createjs.Ticker.on("tick", handleTick); - * function handleTick(event) { - * stage.update(event); - * } - * - *

Example

- * To define a simple sprite sheet, with a single image "sprites.jpg" arranged in a regular 50x50 grid with three - * animations: "stand" showing the first frame, "run" looping frame 1-5 inclusive, and "jump" playing frame 6-8 and - * sequencing back to run. - * - * var data = { - * images: ["sprites.jpg"], - * frames: {width:50, height:50}, - * animations: { - * stand:0, - * run:[1,5], - * jump:[6,8,"run"] - * } - * }; - * var spriteSheet = new createjs.SpriteSheet(data); - * var animation = new createjs.Sprite(spriteSheet, "run"); - * - *

Generating SpriteSheet Images

- * Spritesheets can be created manually by combining images in PhotoShop, and specifying the frame size or - * coordinates manually, however there are a number of tools that facilitate this. - *
    - *
  • Exporting SpriteSheets or HTML5 content from Flash Pro supports the EaselJS SpriteSheet format.
  • - *
  • The popular Texture Packer has - * EaselJS support. - *
  • SWF animations in Flash can be exported to SpriteSheets using
  • - *
- * - *

Cross Origin Issues

- * Warning: Images loaded cross-origin will throw cross-origin security errors when interacted with - * using: - *
    - *
  • a mouse
  • - *
  • methods such as {{#crossLink "Container/getObjectUnderPoint"}}{{/crossLink}}
  • - *
  • Filters (see {{#crossLink "Filter"}}{{/crossLink}})
  • - *
  • caching (see {{#crossLink "DisplayObject/cache"}}{{/crossLink}})
  • - *
- * You can get around this by setting `crossOrigin` property on your images before passing them to EaselJS, or - * setting the `crossOrigin` property on PreloadJS' LoadQueue or LoadItems. - * - * var image = new Image(); - * img.crossOrigin="Anonymous"; - * img.src = "http://server-with-CORS-support.com/path/to/image.jpg"; - * - * If you pass string paths to SpriteSheets, they will not work cross-origin. The server that stores the image must - * support cross-origin requests, or this will not work. For more information, check out - * CORS overview on MDN. - * - * @class SpriteSheet - * @constructor - * @param {Object} data An object describing the SpriteSheet data. - * @extends EventDispatcher - **/ - function SpriteSheet(data) { - this.EventDispatcher_constructor(); - - - // public properties: - /** - * Indicates whether all images are finished loading. - * @property complete - * @type Boolean - * @readonly - **/ - this.complete = true; - - /** - * Specifies the framerate to use by default for Sprite instances using the SpriteSheet. See the Sprite class - * {{#crossLink "Sprite/framerate:property"}}{{/crossLink}} for more information. - * @property framerate - * @type Number - **/ - this.framerate = 0; - - - // private properties: - /** - * @property _animations - * @protected - * @type Array - **/ - this._animations = null; - - /** - * @property _frames - * @protected - * @type Array - **/ - this._frames = null; - - /** - * @property _images - * @protected - * @type Array - **/ - this._images = null; - - /** - * @property _data - * @protected - * @type Object - **/ - this._data = null; - - /** - * @property _loadCount - * @protected - * @type Number - **/ - this._loadCount = 0; - - // only used for simple frame defs: - /** - * @property _frameHeight - * @protected - * @type Number - **/ - this._frameHeight = 0; - - /** - * @property _frameWidth - * @protected - * @type Number - **/ - this._frameWidth = 0; - - /** - * @property _numFrames - * @protected - * @type Number - **/ - this._numFrames = 0; - - /** - * @property _regX - * @protected - * @type Number - **/ - this._regX = 0; - - /** - * @property _regY - * @protected - * @type Number - **/ - this._regY = 0; - - /** - * @property _spacing - * @protected - * @type Number - **/ - this._spacing = 0; - - /** - * @property _margin - * @protected - * @type Number - **/ - this._margin = 0; - - // setup: - this._parseData(data); - } - var p = createjs.extend(SpriteSheet, createjs.EventDispatcher); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// events: - /** - * Dispatched when all images are loaded. Note that this only fires if the images - * were not fully loaded when the sprite sheet was initialized. You should check the complete property - * to prior to adding a listener. Ex. - * - * var sheet = new createjs.SpriteSheet(data); - * if (!sheet.complete) { - * // not preloaded, listen for the complete event: - * sheet.addEventListener("complete", handler); - * } - * - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.6.0 - */ - - /** - * Dispatched when getFrame is called with a valid frame index. This is primarily intended for use by {{#crossLink "SpriteSheetBuilder"}}{{/crossLink}} - * when doing on-demand rendering. - * @event getframe - * @param {Number} index The frame index. - * @param {Object} frame The frame object that getFrame will return. - */ - - /** - * Dispatched when an image encounters an error. A SpriteSheet will dispatch an error event for each image that - * encounters an error, and will still dispatch a {{#crossLink "SpriteSheet/complete:event"}}{{/crossLink}} - * event once all images are finished processing, even if an error is encountered. - * @event error - * @param {String} src The source of the image that failed to load. - * @since 0.8.2 - */ - - -// getter / setters: - /** - * Use the {{#crossLink "SpriteSheet/animations:property"}}{{/crossLink}} property instead. - * @method getAnimations - * @return {Array} - * @deprecated - **/ - p.getAnimations = function() { - return this._animations.slice(); - }; - - /** - * Returns an array of all available animation names available on this sprite sheet as strings. - * @property animations - * @type {Array} - * @readonly - **/ - try { - Object.defineProperties(p, { - animations: { get: p.getAnimations } - }); - } catch (e) {} - - -// public methods: - /** - * Returns the total number of frames in the specified animation, or in the whole sprite - * sheet if the animation param is omitted. Returns 0 if the spritesheet relies on calculated frame counts, and - * the images have not been fully loaded. - * @method getNumFrames - * @param {String} animation The name of the animation to get a frame count for. - * @return {Number} The number of frames in the animation, or in the entire sprite sheet if the animation param is omitted. - */ - p.getNumFrames = function(animation) { - if (animation == null) { - return this._frames ? this._frames.length : this._numFrames || 0; - } else { - var data = this._data[animation]; - if (data == null) { return 0; } - else { return data.frames.length; } - } - }; - - /** - * Returns an object defining the specified animation. The returned object contains:
    - *
  • frames: an array of the frame ids in the animation
  • - *
  • speed: the playback speed for this animation
  • - *
  • name: the name of the animation
  • - *
  • next: the default animation to play next. If the animation loops, the name and next property will be the - * same.
  • - *
- * @method getAnimation - * @param {String} name The name of the animation to get. - * @return {Object} a generic object with frames, speed, name, and next properties. - **/ - p.getAnimation = function(name) { - return this._data[name]; - }; - - /** - * Returns an object specifying the image and source rect of the specified frame. The returned object has:
    - *
  • an image property holding a reference to the image object in which the frame is found
  • - *
  • a rect property containing a Rectangle instance which defines the boundaries for the frame within that - * image.
  • - *
  • A regX and regY property corresponding to the regX/Y values for the frame. - *
- * @method getFrame - * @param {Number} frameIndex The index of the frame. - * @return {Object} a generic object with image and rect properties. Returns null if the frame does not exist. - **/ - p.getFrame = function(frameIndex) { - var frame; - if (this._frames && (frame=this._frames[frameIndex])) { return frame; } - return null; - }; - - /** - * Returns a {{#crossLink "Rectangle"}}{{/crossLink}} instance defining the bounds of the specified frame relative - * to the origin. For example, a 90 x 70 frame with a regX of 50 and a regY of 40 would return: - * - * [x=-50, y=-40, width=90, height=70] - * - * @method getFrameBounds - * @param {Number} frameIndex The index of the frame. - * @param {Rectangle} [rectangle] A Rectangle instance to copy the values into. By default a new instance is created. - * @return {Rectangle} A Rectangle instance. Returns null if the frame does not exist, or the image is not fully loaded. - **/ - p.getFrameBounds = function(frameIndex, rectangle) { - var frame = this.getFrame(frameIndex); - return frame ? (rectangle||new createjs.Rectangle()).setValues(-frame.regX, -frame.regY, frame.rect.width, frame.rect.height) : null; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[SpriteSheet]"; - }; - - /** - * SpriteSheet cannot be cloned. A SpriteSheet can be shared by multiple Sprite instances without cloning it. - * @method clone - **/ - p.clone = function() { - throw("SpriteSheet cannot be cloned.") - }; - -// private methods: - /** - * @method _parseData - * @param {Object} data An object describing the SpriteSheet data. - * @protected - **/ - p._parseData = function(data) { - var i,l,o,a; - if (data == null) { return; } - - this.framerate = data.framerate||0; - - // parse images: - if (data.images && (l=data.images.length) > 0) { - a = this._images = []; - for (i=0; i= maxFrames) { break imgLoop; } - frameCount++; - this._frames.push({ - image: img, - rect: new createjs.Rectangle(x, y, frameWidth, frameHeight), - regX: this._regX, - regY: this._regY - }); - x += frameWidth+spacing; - } - y += frameHeight+spacing; - } - } - this._numFrames = frameCount; - }; - - - createjs.SpriteSheet = createjs.promote(SpriteSheet, "EventDispatcher"); -}()); - -//############################################################################## -// Graphics.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * The Graphics class exposes an easy to use API for generating vector drawing instructions and drawing them to a - * specified context. Note that you can use Graphics without any dependency on the EaselJS framework by calling {{#crossLink "Graphics/draw"}}{{/crossLink}} - * directly, or it can be used with the {{#crossLink "Shape"}}{{/crossLink}} object to draw vector graphics within the - * context of an EaselJS display list. - * - * There are two approaches to working with Graphics object: calling methods on a Graphics instance (the "Graphics API"), or - * instantiating Graphics command objects and adding them to the graphics queue via {{#crossLink "Graphics/append"}}{{/crossLink}}. - * The former abstracts the latter, simplifying beginning and ending paths, fills, and strokes. - * - * var g = new createjs.Graphics(); - * g.setStrokeStyle(1); - * g.beginStroke("#000000"); - * g.beginFill("red"); - * g.drawCircle(0,0,30); - * - * All drawing methods in Graphics return the Graphics instance, so they can be chained together. For example, - * the following line of code would generate the instructions to draw a rectangle with a red stroke and blue fill: - * - * myGraphics.beginStroke("red").beginFill("blue").drawRect(20, 20, 100, 50); - * - * Each graphics API call generates a command object (see below). The last command to be created can be accessed via - * {{#crossLink "Graphics/command:property"}}{{/crossLink}}: - * - * var fillCommand = myGraphics.beginFill("red").command; - * // ... later, update the fill style/color: - * fillCommand.style = "blue"; - * // or change it to a bitmap fill: - * fillCommand.bitmap(myImage); - * - * For more direct control of rendering, you can instantiate and append command objects to the graphics queue directly. In this case, you - * need to manage path creation manually, and ensure that fill/stroke is applied to a defined path: - * - * // start a new path. Graphics.beginCmd is a reusable BeginPath instance: - * myGraphics.append(createjs.Graphics.beginCmd); - * // we need to define the path before applying the fill: - * var circle = new createjs.Graphics.Circle(0,0,30); - * myGraphics.append(circle); - * // fill the path we just defined: - * var fill = new createjs.Graphics.Fill("red"); - * myGraphics.append(fill); - * - * These approaches can be used together, for example to insert a custom command: - * - * myGraphics.beginFill("red"); - * var customCommand = new CustomSpiralCommand(etc); - * myGraphics.append(customCommand); - * myGraphics.beginFill("blue"); - * myGraphics.drawCircle(0, 0, 30); - * - * See {{#crossLink "Graphics/append"}}{{/crossLink}} for more info on creating custom commands. - * - *

Tiny API

- * The Graphics class also includes a "tiny API", which is one or two-letter methods that are shortcuts for all of the - * Graphics methods. These methods are great for creating compact instructions, and is used by the Toolkit for CreateJS - * to generate readable code. All tiny methods are marked as protected, so you can view them by enabling protected - * descriptions in the docs. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
TinyMethodTinyMethod
mt{{#crossLink "Graphics/moveTo"}}{{/crossLink}} lt {{#crossLink "Graphics/lineTo"}}{{/crossLink}}
a/at{{#crossLink "Graphics/arc"}}{{/crossLink}} / {{#crossLink "Graphics/arcTo"}}{{/crossLink}} bt{{#crossLink "Graphics/bezierCurveTo"}}{{/crossLink}}
qt{{#crossLink "Graphics/quadraticCurveTo"}}{{/crossLink}} (also curveTo)r{{#crossLink "Graphics/rect"}}{{/crossLink}}
cp{{#crossLink "Graphics/closePath"}}{{/crossLink}} c{{#crossLink "Graphics/clear"}}{{/crossLink}}
f{{#crossLink "Graphics/beginFill"}}{{/crossLink}} lf{{#crossLink "Graphics/beginLinearGradientFill"}}{{/crossLink}}
rf{{#crossLink "Graphics/beginRadialGradientFill"}}{{/crossLink}} bf{{#crossLink "Graphics/beginBitmapFill"}}{{/crossLink}}
ef{{#crossLink "Graphics/endFill"}}{{/crossLink}} ss / sd{{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} / {{#crossLink "Graphics/setStrokeDash"}}{{/crossLink}}
s{{#crossLink "Graphics/beginStroke"}}{{/crossLink}} ls{{#crossLink "Graphics/beginLinearGradientStroke"}}{{/crossLink}}
rs{{#crossLink "Graphics/beginRadialGradientStroke"}}{{/crossLink}} bs{{#crossLink "Graphics/beginBitmapStroke"}}{{/crossLink}}
es{{#crossLink "Graphics/endStroke"}}{{/crossLink}} dr{{#crossLink "Graphics/drawRect"}}{{/crossLink}}
rr{{#crossLink "Graphics/drawRoundRect"}}{{/crossLink}} rc{{#crossLink "Graphics/drawRoundRectComplex"}}{{/crossLink}}
dc{{#crossLink "Graphics/drawCircle"}}{{/crossLink}} de{{#crossLink "Graphics/drawEllipse"}}{{/crossLink}}
dp{{#crossLink "Graphics/drawPolyStar"}}{{/crossLink}} p{{#crossLink "Graphics/decodePath"}}{{/crossLink}}
- * - * Here is the above example, using the tiny API instead. - * - * myGraphics.s("red").f("blue").r(20, 20, 100, 50); - * - * @class Graphics - * @constructor - **/ - function Graphics() { - - - // public properties - /** - * Holds a reference to the last command that was created or appended. For example, you could retain a reference - * to a Fill command in order to dynamically update the color later by using: - * - * var myFill = myGraphics.beginFill("red").command; - * // update color later: - * myFill.style = "yellow"; - * - * @property command - * @type Object - **/ - this.command = null; - - - // private properties - /** - * @property _stroke - * @protected - * @type {Stroke} - **/ - this._stroke = null; - - /** - * @property _strokeStyle - * @protected - * @type {StrokeStyle} - **/ - this._strokeStyle = null; - - /** - * @property _oldStrokeStyle - * @protected - * @type {StrokeStyle} - **/ - this._oldStrokeStyle = null; - - /** - * @property _strokeDash - * @protected - * @type {StrokeDash} - **/ - this._strokeDash = null; - - /** - * @property _oldStrokeDash - * @protected - * @type {StrokeDash} - **/ - this._oldStrokeDash = null; - - /** - * @property _strokeIgnoreScale - * @protected - * @type Boolean - **/ - this._strokeIgnoreScale = false; - - /** - * @property _fill - * @protected - * @type {Fill} - **/ - this._fill = null; - - /** - * @property _instructions - * @protected - * @type {Array} - **/ - this._instructions = []; - - /** - * Indicates the last instruction index that was committed. - * @property _commitIndex - * @protected - * @type {Number} - **/ - this._commitIndex = 0; - - /** - * Uncommitted instructions. - * @property _activeInstructions - * @protected - * @type {Array} - **/ - this._activeInstructions = []; - - /** - * This indicates that there have been changes to the activeInstruction list since the last updateInstructions call. - * @property _dirty - * @protected - * @type {Boolean} - * @default false - **/ - this._dirty = false; - - /** - * Index to draw from if a store operation has happened. - * @property _storeIndex - * @protected - * @type {Number} - * @default 0 - **/ - this._storeIndex = 0; - - // setup: - this.clear(); - } - var p = Graphics.prototype; - var G = Graphics; // shortcut - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// static public methods: - /** - * Returns a CSS compatible color string based on the specified RGB numeric color values in the format - * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)". For example, - * - * createjs.Graphics.getRGB(50, 100, 150, 0.5); - * // Returns "rgba(50,100,150,0.5)" - * - * It also supports passing a single hex color value as the first param, and an optional alpha value as the second - * param. For example, - * - * createjs.Graphics.getRGB(0xFF00FF, 0.2); - * // Returns "rgba(255,0,255,0.2)" - * - * @method getRGB - * @static - * @param {Number} r The red component for the color, between 0 and 0xFF (255). - * @param {Number} g The green component for the color, between 0 and 0xFF (255). - * @param {Number} b The blue component for the color, between 0 and 0xFF (255). - * @param {Number} [alpha] The alpha component for the color where 0 is fully transparent and 1 is fully opaque. - * @return {String} A CSS compatible color string based on the specified RGB numeric color values in the format - * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)". - **/ - Graphics.getRGB = function(r, g, b, alpha) { - if (r != null && b == null) { - alpha = g; - b = r&0xFF; - g = r>>8&0xFF; - r = r>>16&0xFF; - } - if (alpha == null) { - return "rgb("+r+","+g+","+b+")"; - } else { - return "rgba("+r+","+g+","+b+","+alpha+")"; - } - }; - - /** - * Returns a CSS compatible color string based on the specified HSL numeric color values in the format "hsla(360,100,100,1.0)", - * or if alpha is null then in the format "hsl(360,100,100)". - * - * createjs.Graphics.getHSL(150, 100, 70); - * // Returns "hsl(150,100,70)" - * - * @method getHSL - * @static - * @param {Number} hue The hue component for the color, between 0 and 360. - * @param {Number} saturation The saturation component for the color, between 0 and 100. - * @param {Number} lightness The lightness component for the color, between 0 and 100. - * @param {Number} [alpha] The alpha component for the color where 0 is fully transparent and 1 is fully opaque. - * @return {String} A CSS compatible color string based on the specified HSL numeric color values in the format - * "hsla(360,100,100,1.0)", or if alpha is null then in the format "hsl(360,100,100)". - **/ - Graphics.getHSL = function(hue, saturation, lightness, alpha) { - if (alpha == null) { - return "hsl("+(hue%360)+","+saturation+"%,"+lightness+"%)"; - } else { - return "hsla("+(hue%360)+","+saturation+"%,"+lightness+"%,"+alpha+")"; - } - }; - - -// static properties: - /** - * A reusable instance of {{#crossLink "Graphics/BeginPath"}}{{/crossLink}} to avoid - * unnecessary instantiation. - * @property beginCmd - * @type {Graphics.BeginPath} - * @static - **/ - // defined at the bottom of this file. - - /** - * Map of Base64 characters to values. Used by {{#crossLink "Graphics/decodePath"}}{{/crossLink}}. - * @property BASE_64 - * @static - * @final - * @readonly - * @type {Object} - **/ - Graphics.BASE_64 = {"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"+":62,"/":63}; - - /** - * Maps numeric values for the caps parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to - * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to - * "butt", 1 to "round", and 2 to "square". - * For example, to set the line caps to "square": - * - * myGraphics.ss(16, 2); - * - * @property STROKE_CAPS_MAP - * @static - * @final - * @readonly - * @type {Array} - **/ - Graphics.STROKE_CAPS_MAP = ["butt", "round", "square"]; - - /** - * Maps numeric values for the joints parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to - * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to - * "miter", 1 to "round", and 2 to "bevel". - * For example, to set the line joints to "bevel": - * - * myGraphics.ss(16, 0, 2); - * - * @property STROKE_JOINTS_MAP - * @static - * @final - * @readonly - * @type {Array} - **/ - Graphics.STROKE_JOINTS_MAP = ["miter", "round", "bevel"]; - - /** - * @property _ctx - * @static - * @protected - * @type {CanvasRenderingContext2D} - **/ - var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas")); - if (canvas.getContext) { - Graphics._ctx = canvas.getContext("2d"); - canvas.width = canvas.height = 1; - } - - -// getter / setters: - /** - * Use the {{#crossLink "Graphics/instructions:property"}}{{/crossLink}} property instead. - * @method getInstructions - * @return {Array} - * @deprecated - **/ - p.getInstructions = function() { - this._updateInstructions(); - return this._instructions; - }; - - /** - * Returns the graphics instructions array. Each entry is a graphics command object (ex. Graphics.Fill, Graphics.Rect) - * Modifying the returned array directly is not recommended, and is likely to result in unexpected behaviour. - * - * This property is mainly intended for introspection of the instructions (ex. for graphics export). - * @property instructions - * @type {Array} - * @readonly - **/ - try { - Object.defineProperties(p, { - instructions: { get: p.getInstructions } - }); - } catch (e) {} - - -// public methods: - /** - * Returns true if this Graphics instance has no drawing commands. - * @method isEmpty - * @return {Boolean} Returns true if this Graphics instance has no drawing commands. - **/ - p.isEmpty = function() { - return !(this._instructions.length || this._activeInstructions.length); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Object} data Optional data that is passed to graphics command exec methods. When called from a Shape instance, the shape passes itself as the data parameter. This can be used by custom graphic commands to insert contextual data. - **/ - p.draw = function(ctx, data) { - this._updateInstructions(); - var instr = this._instructions; - for (var i=this._storeIndex, l=instr.length; iDisplayObject.mask to draw the clipping path, for example. - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method drawAsPath - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - **/ - p.drawAsPath = function(ctx) { - this._updateInstructions(); - var instr, instrs = this._instructions; - for (var i=this._storeIndex, l=instrs.length; i - * whatwg spec. - * @method lineTo - * @param {Number} x The x coordinate the drawing point should draw to. - * @param {Number} y The y coordinate the drawing point should draw to. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.lineTo = function(x, y) { - return this.append(new G.LineTo(x,y)); - }; - - /** - * Draws an arc with the specified control points and radius. For detailed information, read the - * - * whatwg spec. A tiny API method "at" also exists. - * @method arcTo - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} radius - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.arcTo = function(x1, y1, x2, y2, radius) { - return this.append(new G.ArcTo(x1, y1, x2, y2, radius)); - }; - - /** - * Draws an arc defined by the radius, startAngle and endAngle arguments, centered at the position (x, y). For - * example, to draw a full circle with a radius of 20 centered at (100, 100): - * - * arc(100, 100, 20, 0, Math.PI*2); - * - * For detailed information, read the - * whatwg spec. - * A tiny API method "a" also exists. - * @method arc - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} startAngle Measured in radians. - * @param {Number} endAngle Measured in radians. - * @param {Boolean} anticlockwise - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) { - return this.append(new G.Arc(x, y, radius, startAngle, endAngle, anticlockwise)); - }; - - /** - * Draws a quadratic curve from the current drawing point to (x, y) using the control point (cpx, cpy). For detailed - * information, read the - * whatwg spec. A tiny API method "qt" also exists. - * @method quadraticCurveTo - * @param {Number} cpx - * @param {Number} cpy - * @param {Number} x - * @param {Number} y - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.quadraticCurveTo = function(cpx, cpy, x, y) { - return this.append(new G.QuadraticCurveTo(cpx, cpy, x, y)); - }; - - /** - * Draws a bezier curve from the current drawing point to (x, y) using the control points (cp1x, cp1y) and (cp2x, - * cp2y). For detailed information, read the - * - * whatwg spec. A tiny API method "bt" also exists. - * @method bezierCurveTo - * @param {Number} cp1x - * @param {Number} cp1y - * @param {Number} cp2x - * @param {Number} cp2y - * @param {Number} x - * @param {Number} y - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.bezierCurveTo = function(cp1x, cp1y, cp2x, cp2y, x, y) { - return this.append(new G.BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)); - }; - - /** - * Draws a rectangle at (x, y) with the specified width and height using the current fill and/or stroke. - * For detailed information, read the - * - * whatwg spec. A tiny API method "r" also exists. - * @method rect - * @param {Number} x - * @param {Number} y - * @param {Number} w Width of the rectangle - * @param {Number} h Height of the rectangle - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.rect = function(x, y, w, h) { - return this.append(new G.Rect(x, y, w, h)); - }; - - /** - * Closes the current path, effectively drawing a line from the current drawing point to the first drawing point specified - * since the fill or stroke was last set. A tiny API method "cp" also exists. - * @method closePath - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.closePath = function() { - return this._activeInstructions.length ? this.append(new G.ClosePath()) : this; - }; - - -// public methods that roughly map to Flash graphics APIs: - /** - * Clears all drawing instructions, effectively resetting this Graphics instance. Any line and fill styles will need - * to be redefined to draw shapes following a clear call. A tiny API method "c" also exists. - * @method clear - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.clear = function() { - this._instructions.length = this._activeInstructions.length = this._commitIndex = 0; - this._strokeStyle = this._oldStrokeStyle = this._stroke = this._fill = this._strokeDash = this._oldStrokeDash = null; - this._dirty = this._strokeIgnoreScale = false; - return this; - }; - - /** - * Begins a fill with the specified color. This ends the current sub-path. A tiny API method "f" also exists. - * @method beginFill - * @param {String} color A CSS compatible color value (ex. "red", "#FF0000", or "rgba(255,0,0,0.5)"). Setting to - * null will result in no fill. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginFill = function(color) { - return this._setFill(color ? new G.Fill(color) : null); - }; - - /** - * Begins a linear gradient fill defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For - * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a - * square to display it: - * - * myGraphics.beginLinearGradientFill(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120); - * - * A tiny API method "lf" also exists. - * @method beginLinearGradientFill - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define a gradient - * drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, 0.9] would draw - * the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. - * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginLinearGradientFill = function(colors, ratios, x0, y0, x1, y1) { - return this._setFill(new G.Fill().linearGradient(colors, ratios, x0, y0, x1, y1)); - }; - - /** - * Begins a radial gradient fill. This ends the current sub-path. For example, the following code defines a red to - * blue radial gradient centered at (100, 100), with a radius of 50, and draws a circle to display it: - * - * myGraphics.beginRadialGradientFill(["#F00","#00F"], [0, 1], 100, 100, 0, 100, 100, 50).drawCircle(100, 100, 50); - * - * A tiny API method "rf" also exists. - * @method beginRadialGradientFill - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 Center position of the inner circle that defines the gradient. - * @param {Number} y0 Center position of the inner circle that defines the gradient. - * @param {Number} r0 Radius of the inner circle that defines the gradient. - * @param {Number} x1 Center position of the outer circle that defines the gradient. - * @param {Number} y1 Center position of the outer circle that defines the gradient. - * @param {Number} r1 Radius of the outer circle that defines the gradient. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginRadialGradientFill = function(colors, ratios, x0, y0, r0, x1, y1, r1) { - return this._setFill(new G.Fill().radialGradient(colors, ratios, x0, y0, r0, x1, y1, r1)); - }; - - /** - * Begins a pattern fill using the specified image. This ends the current sub-path. A tiny API method "bf" also - * exists. - * @method beginBitmapFill - * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use - * as the pattern. Must be loaded prior to creating a bitmap fill, or the fill will be empty. - * @param {String} repetition Optional. Indicates whether to repeat the image in the fill area. One of "repeat", - * "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". Note that Firefox does not support "repeat-x" or - * "repeat-y" (latest tests were in FF 20.0), and will default to "repeat". - * @param {Matrix2D} matrix Optional. Specifies a transformation matrix for the bitmap fill. This transformation - * will be applied relative to the parent transform. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginBitmapFill = function(image, repetition, matrix) { - return this._setFill(new G.Fill(null,matrix).bitmap(image, repetition)); - }; - - /** - * Ends the current sub-path, and begins a new one with no fill. Functionally identical to beginFill(null). - * A tiny API method "ef" also exists. - * @method endFill - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.endFill = function() { - return this.beginFill(); - }; - - /** - * Sets the stroke style. Like all drawing methods, this can be chained, so you can define - * the stroke style and color in a single line of code like so: - * - * myGraphics.setStrokeStyle(8,"round").beginStroke("#F00"); - * - * A tiny API method "ss" also exists. - * @method setStrokeStyle - * @param {Number} thickness The width of the stroke. - * @param {String | Number} [caps=0] Indicates the type of caps to use at the end of lines. One of butt, - * round, or square. Defaults to "butt". Also accepts the values 0 (butt), 1 (round), and 2 (square) for use with - * the tiny API. - * @param {String | Number} [joints=0] Specifies the type of joints that should be used where two lines meet. - * One of bevel, round, or miter. Defaults to "miter". Also accepts the values 0 (miter), 1 (round), and 2 (bevel) - * for use with the tiny API. - * @param {Number} [miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which - * controls at what point a mitered joint will be clipped. - * @param {Boolean} [ignoreScale=false] If true, the stroke will be drawn at the specified thickness regardless - * of active transformations. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.setStrokeStyle = function(thickness, caps, joints, miterLimit, ignoreScale) { - this._updateInstructions(true); - this._strokeStyle = this.command = new G.StrokeStyle(thickness, caps, joints, miterLimit, ignoreScale); - - // ignoreScale lives on Stroke, not StrokeStyle, so we do a little trickery: - if (this._stroke) { this._stroke.ignoreScale = ignoreScale; } - this._strokeIgnoreScale = ignoreScale; - return this; - }; - - /** - * Sets or clears the stroke dash pattern. - * - * myGraphics.setStrokeDash([20, 10], 0); - * - * A tiny API method `sd` also exists. - * @method setStrokeDash - * @param {Array} [segments] An array specifying the dash pattern, alternating between line and gap. - * For example, `[20,10]` would create a pattern of 20 pixel lines with 10 pixel gaps between them. - * Passing null or an empty array will clear the existing stroke dash. - * @param {Number} [offset=0] The offset of the dash pattern. For example, you could increment this value to create a "marching ants" effect. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.setStrokeDash = function(segments, offset) { - this._updateInstructions(true); - this._strokeDash = this.command = new G.StrokeDash(segments, offset); - return this; - }; - - /** - * Begins a stroke with the specified color. This ends the current sub-path. A tiny API method "s" also exists. - * @method beginStroke - * @param {String} color A CSS compatible color value (ex. "#FF0000", "red", or "rgba(255,0,0,0.5)"). Setting to - * null will result in no stroke. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginStroke = function(color) { - return this._setStroke(color ? new G.Stroke(color) : null); - }; - - /** - * Begins a linear gradient stroke defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For - * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a - * square to display it: - * - * myGraphics.setStrokeStyle(10). - * beginLinearGradientStroke(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120); - * - * A tiny API method "ls" also exists. - * @method beginLinearGradientStroke - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. - * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginLinearGradientStroke = function(colors, ratios, x0, y0, x1, y1) { - return this._setStroke(new G.Stroke().linearGradient(colors, ratios, x0, y0, x1, y1)); - }; - - /** - * Begins a radial gradient stroke. This ends the current sub-path. For example, the following code defines a red to - * blue radial gradient centered at (100, 100), with a radius of 50, and draws a rectangle to display it: - * - * myGraphics.setStrokeStyle(10) - * .beginRadialGradientStroke(["#F00","#00F"], [0, 1], 100, 100, 0, 100, 100, 50) - * .drawRect(50, 90, 150, 110); - * - * A tiny API method "rs" also exists. - * @method beginRadialGradientStroke - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%, then draw the second color - * to 100%. - * @param {Number} x0 Center position of the inner circle that defines the gradient. - * @param {Number} y0 Center position of the inner circle that defines the gradient. - * @param {Number} r0 Radius of the inner circle that defines the gradient. - * @param {Number} x1 Center position of the outer circle that defines the gradient. - * @param {Number} y1 Center position of the outer circle that defines the gradient. - * @param {Number} r1 Radius of the outer circle that defines the gradient. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginRadialGradientStroke = function(colors, ratios, x0, y0, r0, x1, y1, r1) { - return this._setStroke(new G.Stroke().radialGradient(colors, ratios, x0, y0, r0, x1, y1, r1)); - }; - - /** - * Begins a pattern fill using the specified image. This ends the current sub-path. Note that unlike bitmap fills, - * strokes do not currently support a matrix parameter due to limitations in the canvas API. A tiny API method "bs" - * also exists. - * @method beginBitmapStroke - * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use - * as the pattern. Must be loaded prior to creating a bitmap fill, or the fill will be empty. - * @param {String} [repetition=repeat] Optional. Indicates whether to repeat the image in the fill area. One of - * "repeat", "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.beginBitmapStroke = function(image, repetition) { - // NOTE: matrix is not supported for stroke because transforms on strokes also affect the drawn stroke width. - return this._setStroke(new G.Stroke().bitmap(image, repetition)); - }; - - /** - * Ends the current sub-path, and begins a new one with no stroke. Functionally identical to beginStroke(null). - * A tiny API method "es" also exists. - * @method endStroke - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.endStroke = function() { - return this.beginStroke(); - }; - - /** - * Maps the familiar ActionScript curveTo() method to the functionally similar {{#crossLink "Graphics/quadraticCurveTo"}}{{/crossLink}} - * method. - * @method quadraticCurveTo - * @param {Number} cpx - * @param {Number} cpy - * @param {Number} x - * @param {Number} y - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.curveTo = p.quadraticCurveTo; - - /** - * - * Maps the familiar ActionScript drawRect() method to the functionally similar {{#crossLink "Graphics/rect"}}{{/crossLink}} - * method. - * @method drawRect - * @param {Number} x - * @param {Number} y - * @param {Number} w Width of the rectangle - * @param {Number} h Height of the rectangle - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawRect = p.rect; - - /** - * Draws a rounded rectangle with all corners with the specified radius. - * @method drawRoundRect - * @param {Number} x - * @param {Number} y - * @param {Number} w - * @param {Number} h - * @param {Number} radius Corner radius. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawRoundRect = function(x, y, w, h, radius) { - return this.drawRoundRectComplex(x, y, w, h, radius, radius, radius, radius); - }; - - /** - * Draws a rounded rectangle with different corner radii. Supports positive and negative corner radii. A tiny API - * method "rc" also exists. - * @method drawRoundRectComplex - * @param {Number} x The horizontal coordinate to draw the round rect. - * @param {Number} y The vertical coordinate to draw the round rect. - * @param {Number} w The width of the round rect. - * @param {Number} h The height of the round rect. - * @param {Number} radiusTL Top left corner radius. - * @param {Number} radiusTR Top right corner radius. - * @param {Number} radiusBR Bottom right corner radius. - * @param {Number} radiusBL Bottom left corner radius. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawRoundRectComplex = function(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL) { - return this.append(new G.RoundRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL)); - }; - - /** - * Draws a circle with the specified radius at (x, y). - * - * var g = new createjs.Graphics(); - * g.setStrokeStyle(1); - * g.beginStroke(createjs.Graphics.getRGB(0,0,0)); - * g.beginFill(createjs.Graphics.getRGB(255,0,0)); - * g.drawCircle(0,0,3); - * - * var s = new createjs.Shape(g); - * s.x = 100; - * s.y = 100; - * - * stage.addChild(s); - * stage.update(); - * - * A tiny API method "dc" also exists. - * @method drawCircle - * @param {Number} x x coordinate center point of circle. - * @param {Number} y y coordinate center point of circle. - * @param {Number} radius Radius of circle. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawCircle = function(x, y, radius) { - return this.append(new G.Circle(x, y, radius)); - }; - - /** - * Draws an ellipse (oval) with a specified width (w) and height (h). Similar to {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}, - * except the width and height can be different. A tiny API method "de" also exists. - * @method drawEllipse - * @param {Number} x The left coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} - * which draws from center. - * @param {Number} y The top coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} - * which draws from the center. - * @param {Number} w The height (horizontal diameter) of the ellipse. The horizontal radius will be half of this - * number. - * @param {Number} h The width (vertical diameter) of the ellipse. The vertical radius will be half of this number. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawEllipse = function(x, y, w, h) { - return this.append(new G.Ellipse(x, y, w, h)); - }; - - /** - * Draws a star if pointSize is greater than 0, or a regular polygon if pointSize is 0 with the specified number of - * points. For example, the following code will draw a familiar 5 pointed star shape centered at 100, 100 and with a - * radius of 50: - * - * myGraphics.beginFill("#FF0").drawPolyStar(100, 100, 50, 5, 0.6, -90); - * // Note: -90 makes the first point vertical - * - * A tiny API method "dp" also exists. - * - * @method drawPolyStar - * @param {Number} x Position of the center of the shape. - * @param {Number} y Position of the center of the shape. - * @param {Number} radius The outer radius of the shape. - * @param {Number} sides The number of points on the star or sides on the polygon. - * @param {Number} pointSize The depth or "pointy-ness" of the star points. A pointSize of 0 will draw a regular - * polygon (no points), a pointSize of 1 will draw nothing because the points are infinitely pointy. - * @param {Number} angle The angle of the first point / corner. For example a value of 0 will draw the first point - * directly to the right of the center. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.drawPolyStar = function(x, y, radius, sides, pointSize, angle) { - return this.append(new G.PolyStar(x, y, radius, sides, pointSize, angle)); - }; - - // TODO: deprecated. - /** - * Removed in favour of using custom command objects with {{#crossLink "Graphics/append"}}{{/crossLink}}. - * @method inject - * @deprecated - **/ - - /** - * Appends a graphics command object to the graphics queue. Command objects expose an "exec" method - * that accepts two parameters: the Context2D to operate on, and an arbitrary data object passed into - * {{#crossLink "Graphics/draw"}}{{/crossLink}}. The latter will usually be the Shape instance that called draw. - * - * This method is used internally by Graphics methods, such as drawCircle, but can also be used directly to insert - * built-in or custom graphics commands. For example: - * - * // attach data to our shape, so we can access it during the draw: - * myShape.color = "red"; - * - * // append a Circle command object: - * myShape.graphics.append(new createjs.Graphics.Circle(50, 50, 30)); - * - * // append a custom command object with an exec method that sets the fill style - * // based on the shape's data, and then fills the circle. - * myShape.graphics.append({exec:function(ctx, shape) { - * ctx.fillStyle = shape.color; - * ctx.fill(); - * }}); - * - * @method append - * @param {Object} command A graphics command object exposing an "exec" method. - * @param {boolean} clean The clean param is primarily for internal use. A value of true indicates that a command does not generate a path that should be stroked or filled. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.append = function(command, clean) { - this._activeInstructions.push(command); - this.command = command; - if (!clean) { this._dirty = true; } - return this; - }; - - /** - * Decodes a compact encoded path string into a series of draw instructions. - * This format is not intended to be human readable, and is meant for use by authoring tools. - * The format uses a base64 character set, with each character representing 6 bits, to define a series of draw - * commands. - * - * Each command is comprised of a single "header" character followed by a variable number of alternating x and y - * position values. Reading the header bits from left to right (most to least significant): bits 1 to 3 specify the - * type of operation (0-moveTo, 1-lineTo, 2-quadraticCurveTo, 3-bezierCurveTo, 4-closePath, 5-7 unused). Bit 4 - * indicates whether position values use 12 bits (2 characters) or 18 bits (3 characters), with a one indicating the - * latter. Bits 5 and 6 are currently unused. - * - * Following the header is a series of 0 (closePath), 2 (moveTo, lineTo), 4 (quadraticCurveTo), or 6 (bezierCurveTo) - * parameters. These parameters are alternating x/y positions represented by 2 or 3 characters (as indicated by the - * 4th bit in the command char). These characters consist of a 1 bit sign (1 is negative, 0 is positive), followed - * by an 11 (2 char) or 17 (3 char) bit integer value. All position values are in tenths of a pixel. Except in the - * case of move operations which are absolute, this value is a delta from the previous x or y position (as - * appropriate). - * - * For example, the string "A3cAAMAu4AAA" represents a line starting at -150,0 and ending at 150,0. - *
A - bits 000000. First 3 bits (000) indicate a moveTo operation. 4th bit (0) indicates 2 chars per - * parameter. - *
n0 - 110111011100. Absolute x position of -150.0px. First bit indicates a negative value, remaining bits - * indicate 1500 tenths of a pixel. - *
AA - 000000000000. Absolute y position of 0. - *
I - 001100. First 3 bits (001) indicate a lineTo operation. 4th bit (1) indicates 3 chars per parameter. - *
Au4 - 000000101110111000. An x delta of 300.0px, which is added to the previous x value of -150.0px to - * provide an absolute position of +150.0px. - *
AAA - 000000000000000000. A y delta value of 0. - * - * A tiny API method "p" also exists. - * @method decodePath - * @param {String} str The path string to decode. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.decodePath = function(str) { - var instructions = [this.moveTo, this.lineTo, this.quadraticCurveTo, this.bezierCurveTo, this.closePath]; - var paramCount = [2, 2, 4, 6, 0]; - var i=0, l=str.length; - var params = []; - var x=0, y=0; - var base64 = Graphics.BASE_64; - - while (i>3; // highest order bits 1-3 code for operation. - var f = instructions[fi]; - // check that we have a valid instruction & that the unused bits are empty: - if (!f || (n&3)) { throw("bad path data (@"+i+"): "+c); } - var pl = paramCount[fi]; - if (!fi) { x=y=0; } // move operations reset the position. - params.length = 0; - i++; - var charCount = (n>>2&1)+2; // 4th header bit indicates number size for this operation. - for (var p=0; p>5) ? -1 : 1; - num = ((num&31)<<6)|(base64[str.charAt(i+1)]); - if (charCount == 3) { num = (num<<6)|(base64[str.charAt(i+2)]); } - num = sign*num/10; - if (p%2) { x = (num += x); } - else { y = (num += y); } - params[p] = num; - i += charCount; - } - f.apply(this,params); - } - return this; - }; - - /** - * Stores all graphics commands so they won't be executed in future draws. Calling store() a second time adds to - * the existing store. This also affects `drawAsPath()`. - * - * This is useful in cases where you are creating vector graphics in an iterative manner (ex. generative art), so - * that only new graphics need to be drawn (which can provide huge performance benefits), but you wish to retain all - * of the vector instructions for later use (ex. scaling, modifying, or exporting). - * - * Note that calling store() will force the active path (if any) to be ended in a manner similar to changing - * the fill or stroke. - * - * For example, consider a application where the user draws lines with the mouse. As each line segment (or collection of - * segments) are added to a Shape, it can be rasterized using {{#crossLink "DisplayObject/updateCache"}}{{/crossLink}}, - * and then stored, so that it can be redrawn at a different scale when the application is resized, or exported to SVG. - * - * // set up cache: - * myShape.cache(0,0,500,500,scale); - * - * // when the user drags, draw a new line: - * myShape.graphics.moveTo(oldX,oldY).lineTo(newX,newY); - * // then draw it into the existing cache: - * myShape.updateCache("source-over"); - * // store the new line, so it isn't redrawn next time: - * myShape.store(); - * - * // then, when the window resizes, we can re-render at a different scale: - * // first, unstore all our lines: - * myShape.unstore(); - * // then cache using the new scale: - * myShape.cache(0,0,500,500,newScale); - * // finally, store the existing commands again: - * myShape.store(); - * - * @method store - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.store = function() { - this._updateInstructions(true); - this._storeIndex = this._instructions.length; - return this; - }; - - /** - * Unstores any graphics commands that were previously stored using {{#crossLink "Graphics/store"}}{{/crossLink}} - * so that they will be executed in subsequent draw calls. - * - * @method unstore - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.unstore = function() { - this._storeIndex = 0; - return this; - }; - - /** - * Returns a clone of this Graphics instance. Note that the individual command objects are not cloned. - * @method clone - * @return {Graphics} A clone of the current Graphics instance. - **/ - p.clone = function() { - var o = new Graphics(); - o.command = this.command; - o._stroke = this._stroke; - o._strokeStyle = this._strokeStyle; - o._strokeDash = this._strokeDash; - o._strokeIgnoreScale = this._strokeIgnoreScale; - o._fill = this._fill; - o._instructions = this._instructions.slice(); - o._commitIndex = this._commitIndex; - o._activeInstructions = this._activeInstructions.slice(); - o._dirty = this._dirty; - o._storeIndex = this._storeIndex; - return o; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Graphics]"; - }; - - -// tiny API: - /** - * Shortcut to moveTo. - * @method mt - * @param {Number} x The x coordinate the drawing point should move to. - * @param {Number} y The y coordinate the drawing point should move to. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls). - * @chainable - * @protected - **/ - p.mt = p.moveTo; - - /** - * Shortcut to lineTo. - * @method lt - * @param {Number} x The x coordinate the drawing point should draw to. - * @param {Number} y The y coordinate the drawing point should draw to. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.lt = p.lineTo; - - /** - * Shortcut to arcTo. - * @method at - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} x2 - * @param {Number} y2 - * @param {Number} radius - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.at = p.arcTo; - - /** - * Shortcut to bezierCurveTo. - * @method bt - * @param {Number} cp1x - * @param {Number} cp1y - * @param {Number} cp2x - * @param {Number} cp2y - * @param {Number} x - * @param {Number} y - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.bt = p.bezierCurveTo; - - /** - * Shortcut to quadraticCurveTo / curveTo. - * @method qt - * @param {Number} cpx - * @param {Number} cpy - * @param {Number} x - * @param {Number} y - * @protected - * @chainable - **/ - p.qt = p.quadraticCurveTo; - - /** - * Shortcut to arc. - * @method a - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} startAngle Measured in radians. - * @param {Number} endAngle Measured in radians. - * @param {Boolean} anticlockwise - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @protected - * @chainable - **/ - p.a = p.arc; - - /** - * Shortcut to rect. - * @method r - * @param {Number} x - * @param {Number} y - * @param {Number} w Width of the rectangle - * @param {Number} h Height of the rectangle - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.r = p.rect; - - /** - * Shortcut to closePath. - * @method cp - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.cp = p.closePath; - - /** - * Shortcut to clear. - * @method c - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.c = p.clear; - - /** - * Shortcut to beginFill. - * @method f - * @param {String} color A CSS compatible color value (ex. "red", "#FF0000", or "rgba(255,0,0,0.5)"). Setting to - * null will result in no fill. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.f = p.beginFill; - - /** - * Shortcut to beginLinearGradientFill. - * @method lf - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define a gradient - * drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, 0.9] would draw - * the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. - * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.lf = p.beginLinearGradientFill; - - /** - * Shortcut to beginRadialGradientFill. - * @method rf - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 Center position of the inner circle that defines the gradient. - * @param {Number} y0 Center position of the inner circle that defines the gradient. - * @param {Number} r0 Radius of the inner circle that defines the gradient. - * @param {Number} x1 Center position of the outer circle that defines the gradient. - * @param {Number} y1 Center position of the outer circle that defines the gradient. - * @param {Number} r1 Radius of the outer circle that defines the gradient. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.rf = p.beginRadialGradientFill; - - /** - * Shortcut to beginBitmapFill. - * @method bf - * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use - * as the pattern. - * @param {String} repetition Optional. Indicates whether to repeat the image in the fill area. One of "repeat", - * "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". Note that Firefox does not support "repeat-x" or - * "repeat-y" (latest tests were in FF 20.0), and will default to "repeat". - * @param {Matrix2D} matrix Optional. Specifies a transformation matrix for the bitmap fill. This transformation - * will be applied relative to the parent transform. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.bf = p.beginBitmapFill; - - /** - * Shortcut to endFill. - * @method ef - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.ef = p.endFill; - - /** - * Shortcut to setStrokeStyle. - * @method ss - * @param {Number} thickness The width of the stroke. - * @param {String | Number} [caps=0] Indicates the type of caps to use at the end of lines. One of butt, - * round, or square. Defaults to "butt". Also accepts the values 0 (butt), 1 (round), and 2 (square) for use with - * the tiny API. - * @param {String | Number} [joints=0] Specifies the type of joints that should be used where two lines meet. - * One of bevel, round, or miter. Defaults to "miter". Also accepts the values 0 (miter), 1 (round), and 2 (bevel) - * for use with the tiny API. - * @param {Number} [miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which - * controls at what point a mitered joint will be clipped. - * @param {Boolean} [ignoreScale=false] If true, the stroke will be drawn at the specified thickness regardless - * of active transformations. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.ss = p.setStrokeStyle; - - /** - * Shortcut to setStrokeDash. - * @method sd - * @param {Array} [segments] An array specifying the dash pattern, alternating between line and gap. - * For example, [20,10] would create a pattern of 20 pixel lines with 10 pixel gaps between them. - * Passing null or an empty array will clear any existing dash. - * @param {Number} [offset=0] The offset of the dash pattern. For example, you could increment this value to create a "marching ants" effect. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.sd = p.setStrokeDash; - - /** - * Shortcut to beginStroke. - * @method s - * @param {String} color A CSS compatible color value (ex. "#FF0000", "red", or "rgba(255,0,0,0.5)"). Setting to - * null will result in no stroke. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.s = p.beginStroke; - - /** - * Shortcut to beginLinearGradientStroke. - * @method ls - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%. - * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size. - * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size. - * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.ls = p.beginLinearGradientStroke; - - /** - * Shortcut to beginRadialGradientStroke. - * @method rs - * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define - * a gradient drawing from red to blue. - * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, - * 0.9] would draw the first color to 10% then interpolating to the second color at 90%, then draw the second color - * to 100%. - * @param {Number} x0 Center position of the inner circle that defines the gradient. - * @param {Number} y0 Center position of the inner circle that defines the gradient. - * @param {Number} r0 Radius of the inner circle that defines the gradient. - * @param {Number} x1 Center position of the outer circle that defines the gradient. - * @param {Number} y1 Center position of the outer circle that defines the gradient. - * @param {Number} r1 Radius of the outer circle that defines the gradient. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.rs = p.beginRadialGradientStroke; - - /** - * Shortcut to beginBitmapStroke. - * @method bs - * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use - * as the pattern. - * @param {String} [repetition=repeat] Optional. Indicates whether to repeat the image in the fill area. One of - * "repeat", "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.bs = p.beginBitmapStroke; - - /** - * Shortcut to endStroke. - * @method es - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.es = p.endStroke; - - /** - * Shortcut to drawRect. - * @method dr - * @param {Number} x - * @param {Number} y - * @param {Number} w Width of the rectangle - * @param {Number} h Height of the rectangle - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.dr = p.drawRect; - - /** - * Shortcut to drawRoundRect. - * @method rr - * @param {Number} x - * @param {Number} y - * @param {Number} w - * @param {Number} h - * @param {Number} radius Corner radius. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.rr = p.drawRoundRect; - - /** - * Shortcut to drawRoundRectComplex. - * @method rc - * @param {Number} x The horizontal coordinate to draw the round rect. - * @param {Number} y The vertical coordinate to draw the round rect. - * @param {Number} w The width of the round rect. - * @param {Number} h The height of the round rect. - * @param {Number} radiusTL Top left corner radius. - * @param {Number} radiusTR Top right corner radius. - * @param {Number} radiusBR Bottom right corner radius. - * @param {Number} radiusBL Bottom left corner radius. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.rc = p.drawRoundRectComplex; - - /** - * Shortcut to drawCircle. - * @method dc - * @param {Number} x x coordinate center point of circle. - * @param {Number} y y coordinate center point of circle. - * @param {Number} radius Radius of circle. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.dc = p.drawCircle; - - /** - * Shortcut to drawEllipse. - * @method de - * @param {Number} x The left coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} - * which draws from center. - * @param {Number} y The top coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} - * which draws from the center. - * @param {Number} w The height (horizontal diameter) of the ellipse. The horizontal radius will be half of this - * number. - * @param {Number} h The width (vertical diameter) of the ellipse. The vertical radius will be half of this number. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.de = p.drawEllipse; - - /** - * Shortcut to drawPolyStar. - * @method dp - * @param {Number} x Position of the center of the shape. - * @param {Number} y Position of the center of the shape. - * @param {Number} radius The outer radius of the shape. - * @param {Number} sides The number of points on the star or sides on the polygon. - * @param {Number} pointSize The depth or "pointy-ness" of the star points. A pointSize of 0 will draw a regular - * polygon (no points), a pointSize of 1 will draw nothing because the points are infinitely pointy. - * @param {Number} angle The angle of the first point / corner. For example a value of 0 will draw the first point - * directly to the right of the center. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.dp = p.drawPolyStar; - - /** - * Shortcut to decodePath. - * @method p - * @param {String} str The path string to decode. - * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.) - * @chainable - * @protected - **/ - p.p = p.decodePath; - - -// private methods: - /** - * @method _updateInstructions - * @param commit - * @protected - **/ - p._updateInstructions = function(commit) { - var instr = this._instructions, active = this._activeInstructions, commitIndex = this._commitIndex; - - if (this._dirty && active.length) { - instr.length = commitIndex; // remove old, uncommitted commands - instr.push(Graphics.beginCmd); - - var l = active.length, ll = instr.length; - instr.length = ll+l; - for (var i=0; i= 2) { - var o = this.style = Graphics._ctx.createPattern(image, repetition || ""); - o.props = {image: image, repetition: repetition, type: "bitmap"}; - } - return this; - }; - p.path = false; - - /** - * Graphics command object. See {{#crossLink "Graphics/beginStroke"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class Stroke - * @constructor - * @param {Object} style A valid Context2D fillStyle. - * @param {Boolean} ignoreScale - **/ - /** - * A valid Context2D strokeStyle. - * @property style - * @type Object - */ - /** - * @property ignoreScale - * @type Boolean - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - p = (G.Stroke = function(style, ignoreScale) { - this.style = style; - this.ignoreScale = ignoreScale; - }).prototype; - p.exec = function(ctx) { - if (!this.style) { return; } - ctx.strokeStyle = this.style; - if (this.ignoreScale) { ctx.save(); ctx.setTransform(1,0,0,1,0,0); } - ctx.stroke(); - if (this.ignoreScale) { ctx.restore(); } - }; - /** - * Creates a linear gradient style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}. - * See {{#crossLink "Graphics/beginLinearGradientStroke"}}{{/crossLink}} for more information. - * @method linearGradient - * @param {Array} colors - * @param {Array} ratios - * @param {Number} x0 - * @param {Number} y0 - * @param {Number} x1 - * @param {Number} y1 - * @return {Fill} Returns this Stroke object for chaining or assignment. - */ - p.linearGradient = G.Fill.prototype.linearGradient; - /** - * Creates a radial gradient style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}. - * See {{#crossLink "Graphics/beginRadialGradientStroke"}}{{/crossLink}} for more information. - * @method radialGradient - * @param {Array} colors - * @param {Array} ratios - * @param {Number} x0 - * @param {Number} y0 - * @param {Number} r0 - * @param {Number} x1 - * @param {Number} y1 - * @param {Number} r1 - * @return {Fill} Returns this Stroke object for chaining or assignment. - */ - p.radialGradient = G.Fill.prototype.radialGradient; - /** - * Creates a bitmap fill style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}. - * See {{#crossLink "Graphics/beginBitmapStroke"}}{{/crossLink}} for more information. - * @method bitmap - * @param {HTMLImageElement} image - * @param {String} [repetition] One of: repeat, repeat-x, repeat-y, or no-repeat. - * @return {Fill} Returns this Stroke object for chaining or assignment. - */ - p.bitmap = G.Fill.prototype.bitmap; - p.path = false; - - /** - * Graphics command object. See {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class StrokeStyle - * @constructor - * @param {Number} width - * @param {String} [caps=butt] - * @param {String} [joints=miter] - * @param {Number} [miterLimit=10] - * @param {Boolean} [ignoreScale=false] - **/ - /** - * @property width - * @type Number - */ - /** - * One of: butt, round, square - * @property caps - * @type String - */ - /** - * One of: round, bevel, miter - * @property joints - * @type String - */ - /** - * @property miterLimit - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - p = (G.StrokeStyle = function(width, caps, joints, miterLimit, ignoreScale) { - this.width = width; - this.caps = caps; - this.joints = joints; - this.miterLimit = miterLimit; - this.ignoreScale = ignoreScale; - }).prototype; - p.exec = function(ctx) { - ctx.lineWidth = (this.width == null ? "1" : this.width); - ctx.lineCap = (this.caps == null ? "butt" : (isNaN(this.caps) ? this.caps : Graphics.STROKE_CAPS_MAP[this.caps])); - ctx.lineJoin = (this.joints == null ? "miter" : (isNaN(this.joints) ? this.joints : Graphics.STROKE_JOINTS_MAP[this.joints])); - ctx.miterLimit = (this.miterLimit == null ? "10" : this.miterLimit); - ctx.ignoreScale = (this.ignoreScale == null ? false : this.ignoreScale); - }; - p.path = false; - - /** - * Graphics command object. See {{#crossLink "Graphics/setStrokeDash"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class StrokeDash - * @constructor - * @param {Array} [segments] - * @param {Number} [offset=0] - **/ - /** - * @property segments - * @type Array - */ - /** - * @property offset - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - (G.StrokeDash = function(segments, offset) { - this.segments = segments; - this.offset = offset||0; - }).prototype.exec = function(ctx) { - if (ctx.setLineDash) { // feature detection. - ctx.setLineDash(this.segments|| G.StrokeDash.EMPTY_SEGMENTS); // instead of [] to reduce churn. - ctx.lineDashOffset = this.offset||0; - } - }; - /** - * The default value for segments (ie. no dash). - * @property EMPTY_SEGMENTS - * @static - * @final - * @readonly - * @protected - * @type {Array} - **/ - G.StrokeDash.EMPTY_SEGMENTS = []; - - /** - * Graphics command object. See {{#crossLink "Graphics/drawRoundRectComplex"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class RoundRect - * @constructor - * @param {Number} x - * @param {Number} y - * @param {Number} w - * @param {Number} h - * @param {Number} radiusTL - * @param {Number} radiusTR - * @param {Number} radiusBR - * @param {Number} radiusBL - **/ - /** - * @property x - * @type Number - */ - /** - * @property y - * @type Number - */ - /** - * @property w - * @type Number - */ - /** - * @property h - * @type Number - */ - /** - * @property radiusTL - * @type Number - */ - /** - * @property radiusTR - * @type Number - */ - /** - * @property radiusBR - * @type Number - */ - /** - * @property radiusBL - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - (G.RoundRect = function(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL) { - this.x = x; this.y = y; - this.w = w; this.h = h; - this.radiusTL = radiusTL; this.radiusTR = radiusTR; - this.radiusBR = radiusBR; this.radiusBL = radiusBL; - }).prototype.exec = function(ctx) { - var max = (w max) { rTL = max; } - if (rTR < 0) { rTR *= (mTR=-1); } - if (rTR > max) { rTR = max; } - if (rBR < 0) { rBR *= (mBR=-1); } - if (rBR > max) { rBR = max; } - if (rBL < 0) { rBL *= (mBL=-1); } - if (rBL > max) { rBL = max; } - - ctx.moveTo(x+w-rTR, y); - ctx.arcTo(x+w+rTR*mTR, y-rTR*mTR, x+w, y+rTR, rTR); - ctx.lineTo(x+w, y+h-rBR); - ctx.arcTo(x+w+rBR*mBR, y+h+rBR*mBR, x+w-rBR, y+h, rBR); - ctx.lineTo(x+rBL, y+h); - ctx.arcTo(x-rBL*mBL, y+h+rBL*mBL, x, y+h-rBL, rBL); - ctx.lineTo(x, y+rTL); - ctx.arcTo(x-rTL*mTL, y-rTL*mTL, x+rTL, y, rTL); - ctx.closePath(); - }; - - /** - * Graphics command object. See {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class Circle - * @constructor - * @param {Number} x - * @param {Number} y - * @param {Number} radius - **/ - /** - * @property x - * @type Number - */ - /** - * @property y - * @type Number - */ - /** - * @property radius - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - (G.Circle = function(x, y, radius) { - this.x = x; this.y = y; - this.radius = radius; - }).prototype.exec = function(ctx) { ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2); }; - - /** - * Graphics command object. See {{#crossLink "Graphics/drawEllipse"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class Ellipse - * @constructor - * @param {Number} x - * @param {Number} y - * @param {Number} w - * @param {Number} h - **/ - /** - * @property x - * @type Number - */ - /** - * @property y - * @type Number - */ - /** - * @property w - * @type Number - */ - /** - * @property h - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - (G.Ellipse = function(x, y, w, h) { - this.x = x; this.y = y; - this.w = w; this.h = h; - }).prototype.exec = function(ctx) { - var x = this.x, y = this.y; - var w = this.w, h = this.h; - - var k = 0.5522848; - var ox = (w / 2) * k; - var oy = (h / 2) * k; - var xe = x + w; - var ye = y + h; - var xm = x + w / 2; - var ym = y + h / 2; - - ctx.moveTo(x, ym); - ctx.bezierCurveTo(x, ym-oy, xm-ox, y, xm, y); - ctx.bezierCurveTo(xm+ox, y, xe, ym-oy, xe, ym); - ctx.bezierCurveTo(xe, ym+oy, xm+ox, ye, xm, ye); - ctx.bezierCurveTo(xm-ox, ye, x, ym+oy, x, ym); - }; - - /** - * Graphics command object. See {{#crossLink "Graphics/drawPolyStar"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information. - * @class PolyStar - * @constructor - * @param {Number} x - * @param {Number} y - * @param {Number} radius - * @param {Number} sides - * @param {Number} pointSize - * @param {Number} angle - **/ - /** - * @property x - * @type Number - */ - /** - * @property y - * @type Number - */ - /** - * @property radius - * @type Number - */ - /** - * @property sides - * @type Number - */ - /** - * @property pointSize - * @type Number - */ - /** - * @property angle - * @type Number - */ - /** - * Execute the Graphics command in the provided Canvas context. - * @method exec - * @param {CanvasRenderingContext2D} ctx The canvas rendering context - */ - (G.PolyStar = function(x, y, radius, sides, pointSize, angle) { - this.x = x; this.y = y; - this.radius = radius; - this.sides = sides; - this.pointSize = pointSize; - this.angle = angle; - }).prototype.exec = function(ctx) { - var x = this.x, y = this.y; - var radius = this.radius; - var angle = (this.angle||0)/180*Math.PI; - var sides = this.sides; - var ps = 1-(this.pointSize||0); - var a = Math.PI/sides; - - ctx.moveTo(x+Math.cos(angle)*radius, y+Math.sin(angle)*radius); - for (var i=0; iNote: In EaselJS 0.7.0, the mouseEnabled property will not work properly with nested Containers. Please - * check out the latest NEXT version in GitHub for an updated version with this issue resolved. The fix will be - * provided in the next release of EaselJS. - * @property mouseEnabled - * @type {Boolean} - * @default true - **/ - this.mouseEnabled = true; - - /** - * If false, the tick will not run on this display object (or its children). This can provide some performance benefits. - * In addition to preventing the "tick" event from being dispatched, it will also prevent tick related updates - * on some display objects (ex. Sprite & MovieClip frame advancing, DOMElement visibility handling). - * @property tickEnabled - * @type Boolean - * @default true - **/ - this.tickEnabled = true; - - /** - * An optional name for this display object. Included in {{#crossLink "DisplayObject/toString"}}{{/crossLink}} . Useful for - * debugging. - * @property name - * @type {String} - * @default null - **/ - this.name = null; - - /** - * A reference to the {{#crossLink "Container"}}{{/crossLink}} or {{#crossLink "Stage"}}{{/crossLink}} object that - * contains this display object, or null if it has not been added - * to one. - * @property parent - * @final - * @type {Container} - * @default null - * @readonly - **/ - this.parent = null; - - /** - * The left offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate - * around its center, you would set regX and {{#crossLink "DisplayObject/regY:property"}}{{/crossLink}} to 50. - * @property regX - * @type {Number} - * @default 0 - **/ - this.regX = 0; - - /** - * The y offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate around - * its center, you would set {{#crossLink "DisplayObject/regX:property"}}{{/crossLink}} and regY to 50. - * @property regY - * @type {Number} - * @default 0 - **/ - this.regY = 0; - - /** - * The rotation in degrees for this display object. - * @property rotation - * @type {Number} - * @default 0 - **/ - this.rotation = 0; - - /** - * The factor to stretch this display object horizontally. For example, setting scaleX to 2 will stretch the display - * object to twice its nominal width. To horizontally flip an object, set the scale to a negative number. - * @property scaleX - * @type {Number} - * @default 1 - **/ - this.scaleX = 1; - - /** - * The factor to stretch this display object vertically. For example, setting scaleY to 0.5 will stretch the display - * object to half its nominal height. To vertically flip an object, set the scale to a negative number. - * @property scaleY - * @type {Number} - * @default 1 - **/ - this.scaleY = 1; - - /** - * The factor to skew this display object horizontally. - * @property skewX - * @type {Number} - * @default 0 - **/ - this.skewX = 0; - - /** - * The factor to skew this display object vertically. - * @property skewY - * @type {Number} - * @default 0 - **/ - this.skewY = 0; - - /** - * A shadow object that defines the shadow to render on this display object. Set to `null` to remove a shadow. If - * null, this property is inherited from the parent container. - * @property shadow - * @type {Shadow} - * @default null - **/ - this.shadow = null; - - /** - * Indicates whether this display object should be rendered to the canvas and included when running the Stage - * {{#crossLink "Stage/getObjectsUnderPoint"}}{{/crossLink}} method. - * @property visible - * @type {Boolean} - * @default true - **/ - this.visible = true; - - /** - * The x (horizontal) position of the display object, relative to its parent. - * @property x - * @type {Number} - * @default 0 - **/ - this.x = 0; - - /** The y (vertical) position of the display object, relative to its parent. - * @property y - * @type {Number} - * @default 0 - **/ - this.y = 0; - - /** - * If set, defines the transformation for this display object, overriding all other transformation properties - * (x, y, rotation, scale, skew). - * @property transformMatrix - * @type {Matrix2D} - * @default null - **/ - this.transformMatrix = null; - - /** - * The composite operation indicates how the pixels of this display object will be composited with the elements - * behind it. If `null`, this property is inherited from the parent container. For more information, read the - * - * whatwg spec on compositing. - * @property compositeOperation - * @type {String} - * @default null - **/ - this.compositeOperation = null; - - /** - * Indicates whether the display object should be drawn to a whole pixel when - * {{#crossLink "Stage/snapToPixelEnabled"}}{{/crossLink}} is true. To enable/disable snapping on whole - * categories of display objects, set this value on the prototype (Ex. Text.prototype.snapToPixel = true). - * @property snapToPixel - * @type {Boolean} - * @default true - **/ - this.snapToPixel = true; - - /** - * An array of Filter objects to apply to this display object. Filters are only applied / updated when {{#crossLink "cache"}}{{/crossLink}} - * or {{#crossLink "updateCache"}}{{/crossLink}} is called on the display object, and only apply to the area that is - * cached. - * @property filters - * @type {Array} - * @default null - **/ - this.filters = null; - - /** - * A Shape instance that defines a vector mask (clipping path) for this display object. The shape's transformation - * will be applied relative to the display object's parent coordinates (as if it were a child of the parent). - * @property mask - * @type {Shape} - * @default null - */ - this.mask = null; - - /** - * A display object that will be tested when checking mouse interactions or testing {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}. - * The hit area will have its transformation applied relative to this display object's coordinate space (as though - * the hit test object were a child of this display object and relative to its regX/Y). The hitArea will be tested - * using only its own `alpha` value regardless of the alpha value on the target display object, or the target's - * ancestors (parents). - * - * If set on a {{#crossLink "Container"}}{{/crossLink}}, children of the Container will not receive mouse events. - * This is similar to setting {{#crossLink "mouseChildren"}}{{/crossLink}} to false. - * - * Note that hitArea is NOT currently used by the `hitTest()` method, nor is it supported for {{#crossLink "Stage"}}{{/crossLink}}. - * @property hitArea - * @type {DisplayObject} - * @default null - */ - this.hitArea = null; - - /** - * A CSS cursor (ex. "pointer", "help", "text", etc) that will be displayed when the user hovers over this display - * object. You must enable mouseover events using the {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}} method to - * use this property. Setting a non-null cursor on a Container will override the cursor set on its descendants. - * @property cursor - * @type {String} - * @default null - */ - this.cursor = null; - - - // private properties: - /** - * @property _cacheOffsetX - * @protected - * @type {Number} - * @default 0 - **/ - this._cacheOffsetX = 0; - - /** - * @property _cacheOffsetY - * @protected - * @type {Number} - * @default 0 - **/ - this._cacheOffsetY = 0; - - /** - * @property _filterOffsetX - * @protected - * @type {Number} - * @default 0 - **/ - this._filterOffsetX = 0; - - /** - * @property _filterOffsetY - * @protected - * @type {Number} - * @default 0 - **/ - this._filterOffsetY = 0; - - /** - * @property _cacheScale - * @protected - * @type {Number} - * @default 1 - **/ - this._cacheScale = 1; - - /** - * @property _cacheDataURLID - * @protected - * @type {Number} - * @default 0 - */ - this._cacheDataURLID = 0; - - /** - * @property _cacheDataURL - * @protected - * @type {String} - * @default null - */ - this._cacheDataURL = null; - - /** - * @property _props - * @protected - * @type {DisplayObject} - * @default null - **/ - this._props = new createjs.DisplayProps(); - - /** - * @property _rectangle - * @protected - * @type {Rectangle} - * @default null - **/ - this._rectangle = new createjs.Rectangle(); - - /** - * @property _bounds - * @protected - * @type {Rectangle} - * @default null - **/ - this._bounds = null; - } - var p = createjs.extend(DisplayObject, createjs.EventDispatcher); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - -// static properties: - /** - * Listing of mouse event names. Used in _hasMouseEventListener. - * @property _MOUSE_EVENTS - * @protected - * @static - * @type {Array} - **/ - DisplayObject._MOUSE_EVENTS = ["click","dblclick","mousedown","mouseout","mouseover","pressmove","pressup","rollout","rollover"]; - - /** - * Suppresses errors generated when using features like hitTest, mouse events, and {{#crossLink "getObjectsUnderPoint"}}{{/crossLink}} - * with cross domain content. - * @property suppressCrossDomainErrors - * @static - * @type {Boolean} - * @default false - **/ - DisplayObject.suppressCrossDomainErrors = false; - - /** - * @property _snapToPixelEnabled - * @protected - * @static - * @type {Boolean} - * @default false - **/ - DisplayObject._snapToPixelEnabled = false; // stage.snapToPixelEnabled is temporarily copied here during a draw to provide global access. - - /** - * @property _hitTestCanvas - * @type {HTMLCanvasElement | Object} - * @static - * @protected - **/ - /** - * @property _hitTestContext - * @type {CanvasRenderingContext2D} - * @static - * @protected - **/ - var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); // prevent errors on load in browsers without canvas. - if (canvas.getContext) { - DisplayObject._hitTestCanvas = canvas; - DisplayObject._hitTestContext = canvas.getContext("2d"); - canvas.width = canvas.height = 1; - } - - /** - * @property _nextCacheID - * @type {Number} - * @static - * @protected - **/ - DisplayObject._nextCacheID = 1; - - -// events: - /** - * Dispatched when the user presses their left mouse button over the display object. See the - * {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event mousedown - * @since 0.6.0 - */ - - /** - * Dispatched when the user presses their left mouse button and then releases it while over the display object. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event click - * @since 0.6.0 - */ - - /** - * Dispatched when the user double clicks their left mouse button over this display object. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event dblclick - * @since 0.6.0 - */ - - /** - * Dispatched when the user's mouse enters this display object. This event must be enabled using - * {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollover:event"}}{{/crossLink}}. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event mouseover - * @since 0.6.0 - */ - - /** - * Dispatched when the user's mouse leaves this display object. This event must be enabled using - * {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollout:event"}}{{/crossLink}}. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event mouseout - * @since 0.6.0 - */ - - /** - * This event is similar to {{#crossLink "DisplayObject/mouseover:event"}}{{/crossLink}}, with the following - * differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an - * aggregate of their content. - * - * For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over - * shapeA and then directly on to shapeB. With a listener for {{#crossLink "mouseover:event"}}{{/crossLink}} on - * myContainer, two events would be received, each targeting a child element:
    - *
  1. when the mouse enters shapeA (target=shapeA)
  2. - *
  3. when the mouse enters shapeB (target=shapeB)
  4. - *
- * However, with a listener for "rollover" instead, only a single event is received when the mouse first enters - * the aggregate myContainer content (target=myContainer). - * - * This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event rollover - * @since 0.7.0 - */ - - /** - * This event is similar to {{#crossLink "DisplayObject/mouseout:event"}}{{/crossLink}}, with the following - * differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an - * aggregate of their content. - * - * For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over - * shapeA, then directly on to shapeB, then off both. With a listener for {{#crossLink "mouseout:event"}}{{/crossLink}} - * on myContainer, two events would be received, each targeting a child element:
    - *
  1. when the mouse leaves shapeA (target=shapeA)
  2. - *
  3. when the mouse leaves shapeB (target=shapeB)
  4. - *
- * However, with a listener for "rollout" instead, only a single event is received when the mouse leaves - * the aggregate myContainer content (target=myContainer). - * - * This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event rollout - * @since 0.7.0 - */ - - /** - * After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressmove - * event will be generated on that object whenever the mouse moves until the mouse press is released. This can be - * useful for dragging and similar operations. - * @event pressmove - * @since 0.7.0 - */ - - /** - * After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressup event - * will be generated on that object when that mouse press is released. This can be useful for dragging and similar - * operations. - * @event pressup - * @since 0.7.0 - */ - - /** - * Dispatched when the display object is added to a parent container. - * @event added - */ - - /** - * Dispatched when the display object is removed from its parent container. - * @event removed - */ - - /** - * Dispatched on each display object on a stage whenever the stage updates. This occurs immediately before the - * rendering (draw) pass. When {{#crossLink "Stage/update"}}{{/crossLink}} is called, first all display objects on - * the stage dispatch the tick event, then all of the display objects are drawn to stage. Children will have their - * {{#crossLink "tick:event"}}{{/crossLink}} event dispatched in order of their depth prior to the event being - * dispatched on their parent. - * @event tick - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Array} params An array containing any arguments that were passed to the Stage.update() method. For - * example if you called stage.update("hello"), then the params would be ["hello"]. - * @since 0.6.0 - */ - - -// getter / setters: - /** - * Use the {{#crossLink "DisplayObject/stage:property"}}{{/crossLink}} property instead. - * @method getStage - * @return {Stage} - * @deprecated - **/ - p.getStage = function() { - // uses dynamic access to avoid circular dependencies; - var o = this, _Stage = createjs["Stage"]; - while (o.parent) { o = o.parent; } - if (o instanceof _Stage) { return o; } - return null; - }; - - /** - * Returns the Stage instance that this display object will be rendered on, or null if it has not been added to one. - * @property stage - * @type {Stage} - * @readonly - **/ - try { - Object.defineProperties(p, { - stage: { get: p.getStage } - }); - } catch (e) {} - - -// public methods: - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. For example, - * used for drawing the cache (to prevent it from simply drawing an existing cache back into itself). - * @return {Boolean} - **/ - p.draw = function(ctx, ignoreCache) { - var cacheCanvas = this.cacheCanvas; - if (ignoreCache || !cacheCanvas) { return false; } - var scale = this._cacheScale; - ctx.drawImage(cacheCanvas, this._cacheOffsetX+this._filterOffsetX, this._cacheOffsetY+this._filterOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale); - return true; - }; - - /** - * Applies this display object's transformation, alpha, globalCompositeOperation, clipping path (mask), and shadow - * to the specified context. This is typically called prior to {{#crossLink "DisplayObject/draw"}}{{/crossLink}}. - * @method updateContext - * @param {CanvasRenderingContext2D} ctx The canvas 2D to update. - **/ - p.updateContext = function(ctx) { - var o=this, mask=o.mask, mtx= o._props.matrix; - - if (mask && mask.graphics && !mask.graphics.isEmpty()) { - mask.getMatrix(mtx); - ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty); - - mask.graphics.drawAsPath(ctx); - ctx.clip(); - - mtx.invert(); - ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty); - } - - this.getMatrix(mtx); - var tx = mtx.tx, ty = mtx.ty; - if (DisplayObject._snapToPixelEnabled && o.snapToPixel) { - tx = tx + (tx < 0 ? -0.5 : 0.5) | 0; - ty = ty + (ty < 0 ? -0.5 : 0.5) | 0; - } - ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, tx, ty); - ctx.globalAlpha *= o.alpha; - if (o.compositeOperation) { ctx.globalCompositeOperation = o.compositeOperation; } - if (o.shadow) { this._applyShadow(ctx, o.shadow); } - }; - - /** - * Draws the display object into a new canvas, which is then used for subsequent draws. For complex content - * that does not change frequently (ex. a Container with many children that do not move, or a complex vector Shape), - * this can provide for much faster rendering because the content does not need to be re-rendered each tick. The - * cached display object can be moved, rotated, faded, etc freely, however if its content changes, you must - * manually update the cache by calling updateCache() or cache() again. You must specify - * the cache area via the x, y, w, and h parameters. This defines the rectangle that will be rendered and cached - * using this display object's coordinates. - * - *

Example

- * For example if you defined a Shape that drew a circle at 0, 0 with a radius of 25: - * - * var shape = new createjs.Shape(); - * shape.graphics.beginFill("#ff0000").drawCircle(0, 0, 25); - * myShape.cache(-25, -25, 50, 50); - * - * Note that filters need to be defined before the cache is applied. Check out the {{#crossLink "Filter"}}{{/crossLink}} - * class for more information. Some filters (ex. BlurFilter) will not work as expected in conjunction with the scale param. - * - * Usually, the resulting cacheCanvas will have the dimensions width*scale by height*scale, however some filters (ex. BlurFilter) - * will add padding to the canvas dimensions. - * - * @method cache - * @param {Number} x The x coordinate origin for the cache region. - * @param {Number} y The y coordinate origin for the cache region. - * @param {Number} width The width of the cache region. - * @param {Number} height The height of the cache region. - * @param {Number} [scale=1] The scale at which the cache will be created. For example, if you cache a vector shape using - * myShape.cache(0,0,100,100,2) then the resulting cacheCanvas will be 200x200 px. This lets you scale and rotate - * cached elements with greater fidelity. Default is 1. - **/ - p.cache = function(x, y, width, height, scale) { - // draw to canvas. - scale = scale||1; - if (!this.cacheCanvas) { this.cacheCanvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); } - this._cacheWidth = width; - this._cacheHeight = height; - this._cacheOffsetX = x; - this._cacheOffsetY = y; - this._cacheScale = scale; - this.updateCache(); - }; - - /** - * Redraws the display object to its cache. Calling updateCache without an active cache will throw an error. - * If compositeOperation is null the current cache will be cleared prior to drawing. Otherwise the display object - * will be drawn over the existing cache using the specified compositeOperation. - * - *

Example

- * Clear the current graphics of a cached shape, draw some new instructions, and then update the cache. The new line - * will be drawn on top of the old one. - * - * // Not shown: Creating the shape, and caching it. - * shapeInstance.clear(); - * shapeInstance.setStrokeStyle(3).beginStroke("#ff0000").moveTo(100, 100).lineTo(200,200); - * shapeInstance.updateCache(); - * - * @method updateCache - * @param {String} compositeOperation The compositeOperation to use, or null to clear the cache and redraw it. - * - * whatwg spec on compositing. - **/ - p.updateCache = function(compositeOperation) { - var cacheCanvas = this.cacheCanvas; - if (!cacheCanvas) { throw "cache() must be called before updateCache()"; } - var scale = this._cacheScale, offX = this._cacheOffsetX*scale, offY = this._cacheOffsetY*scale; - var w = this._cacheWidth, h = this._cacheHeight, ctx = cacheCanvas.getContext("2d"); - - var fBounds = this._getFilterBounds(); - offX += (this._filterOffsetX = fBounds.x); - offY += (this._filterOffsetY = fBounds.y); - - w = Math.ceil(w*scale) + fBounds.width; - h = Math.ceil(h*scale) + fBounds.height; - if (w != cacheCanvas.width || h != cacheCanvas.height) { - // TODO: it would be nice to preserve the content if there is a compositeOperation. - cacheCanvas.width = w; - cacheCanvas.height = h; - } else if (!compositeOperation) { - ctx.clearRect(0, 0, w+1, h+1); - } - - ctx.save(); - ctx.globalCompositeOperation = compositeOperation; - ctx.setTransform(scale, 0, 0, scale, -offX, -offY); - this.draw(ctx, true); - // TODO: filters and cache scale don't play well together at present. - this._applyFilters(); - ctx.restore(); - this.cacheID = DisplayObject._nextCacheID++; - }; - - /** - * Clears the current cache. See {{#crossLink "DisplayObject/cache"}}{{/crossLink}} for more information. - * @method uncache - **/ - p.uncache = function() { - this._cacheDataURL = this.cacheCanvas = null; - this.cacheID = this._cacheOffsetX = this._cacheOffsetY = this._filterOffsetX = this._filterOffsetY = 0; - this._cacheScale = 1; - }; - - /** - * Returns a data URL for the cache, or null if this display object is not cached. - * Uses cacheID to ensure a new data URL is not generated if the cache has not changed. - * @method getCacheDataURL - * @return {String} The image data url for the cache. - **/ - p.getCacheDataURL = function() { - if (!this.cacheCanvas) { return null; } - if (this.cacheID != this._cacheDataURLID) { this._cacheDataURL = this.cacheCanvas.toDataURL(); } - return this._cacheDataURL; - }; - - /** - * Transforms the specified x and y position from the coordinate space of the display object - * to the global (stage) coordinate space. For example, this could be used to position an HTML label - * over a specific point on a nested display object. Returns a Point instance with x and y properties - * correlating to the transformed coordinates on the stage. - * - *

Example

- * - * displayObject.x = 300; - * displayObject.y = 200; - * stage.addChild(displayObject); - * var point = displayObject.localToGlobal(100, 100); - * // Results in x=400, y=300 - * - * @method localToGlobal - * @param {Number} x The x position in the source display object to transform. - * @param {Number} y The y position in the source display object to transform. - * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned. - * @return {Point} A Point instance with x and y properties correlating to the transformed coordinates - * on the stage. - **/ - p.localToGlobal = function(x, y, pt) { - return this.getConcatenatedMatrix(this._props.matrix).transformPoint(x,y, pt||new createjs.Point()); - }; - - /** - * Transforms the specified x and y position from the global (stage) coordinate space to the - * coordinate space of the display object. For example, this could be used to determine - * the current mouse position within the display object. Returns a Point instance with x and y properties - * correlating to the transformed position in the display object's coordinate space. - * - *

Example

- * - * displayObject.x = 300; - * displayObject.y = 200; - * stage.addChild(displayObject); - * var point = displayObject.globalToLocal(100, 100); - * // Results in x=-200, y=-100 - * - * @method globalToLocal - * @param {Number} x The x position on the stage to transform. - * @param {Number} y The y position on the stage to transform. - * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned. - * @return {Point} A Point instance with x and y properties correlating to the transformed position in the - * display object's coordinate space. - **/ - p.globalToLocal = function(x, y, pt) { - return this.getConcatenatedMatrix(this._props.matrix).invert().transformPoint(x,y, pt||new createjs.Point()); - }; - - /** - * Transforms the specified x and y position from the coordinate space of this display object to the coordinate - * space of the target display object. Returns a Point instance with x and y properties correlating to the - * transformed position in the target's coordinate space. Effectively the same as using the following code with - * {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}. - * - * var pt = this.localToGlobal(x, y); - * pt = target.globalToLocal(pt.x, pt.y); - * - * @method localToLocal - * @param {Number} x The x position in the source display object to transform. - * @param {Number} y The y position on the source display object to transform. - * @param {DisplayObject} target The target display object to which the coordinates will be transformed. - * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned. - * @return {Point} Returns a Point instance with x and y properties correlating to the transformed position - * in the target's coordinate space. - **/ - p.localToLocal = function(x, y, target, pt) { - pt = this.localToGlobal(x, y, pt); - return target.globalToLocal(pt.x, pt.y, pt); - }; - - /** - * Shortcut method to quickly set the transform properties on the display object. All parameters are optional. - * Omitted parameters will have the default value set. - * - *

Example

- * - * displayObject.setTransform(100, 100, 2, 2); - * - * @method setTransform - * @param {Number} [x=0] The horizontal translation (x position) in pixels - * @param {Number} [y=0] The vertical translation (y position) in pixels - * @param {Number} [scaleX=1] The horizontal scale, as a percentage of 1 - * @param {Number} [scaleY=1] the vertical scale, as a percentage of 1 - * @param {Number} [rotation=0] The rotation, in degrees - * @param {Number} [skewX=0] The horizontal skew factor - * @param {Number} [skewY=0] The vertical skew factor - * @param {Number} [regX=0] The horizontal registration point in pixels - * @param {Number} [regY=0] The vertical registration point in pixels - * @return {DisplayObject} Returns this instance. Useful for chaining commands. - * @chainable - */ - p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) { - this.x = x || 0; - this.y = y || 0; - this.scaleX = scaleX == null ? 1 : scaleX; - this.scaleY = scaleY == null ? 1 : scaleY; - this.rotation = rotation || 0; - this.skewX = skewX || 0; - this.skewY = skewY || 0; - this.regX = regX || 0; - this.regY = regY || 0; - return this; - }; - - /** - * Returns a matrix based on this object's current transform. - * @method getMatrix - * @param {Matrix2D} matrix Optional. A Matrix2D object to populate with the calculated values. If null, a new - * Matrix object is returned. - * @return {Matrix2D} A matrix representing this display object's transform. - **/ - p.getMatrix = function(matrix) { - var o = this, mtx = matrix&&matrix.identity() || new createjs.Matrix2D(); - return o.transformMatrix ? mtx.copy(o.transformMatrix) : mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY); - }; - - /** - * Generates a Matrix2D object representing the combined transform of the display object and all of its - * parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}). This can - * be used to transform positions between coordinate spaces, such as with {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} - * and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}. - * @method getConcatenatedMatrix - * @param {Matrix2D} [matrix] A {{#crossLink "Matrix2D"}}{{/crossLink}} object to populate with the calculated values. - * If null, a new Matrix2D object is returned. - * @return {Matrix2D} The combined matrix. - **/ - p.getConcatenatedMatrix = function(matrix) { - var o = this, mtx = this.getMatrix(matrix); - while (o = o.parent) { - mtx.prependMatrix(o.getMatrix(o._props.matrix)); - } - return mtx; - }; - - /** - * Generates a DisplayProps object representing the combined display properties of the object and all of its - * parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}). - * @method getConcatenatedDisplayProps - * @param {DisplayProps} [props] A {{#crossLink "DisplayProps"}}{{/crossLink}} object to populate with the calculated values. - * If null, a new DisplayProps object is returned. - * @return {DisplayProps} The combined display properties. - **/ - p.getConcatenatedDisplayProps = function(props) { - props = props ? props.identity() : new createjs.DisplayProps(); - var o = this, mtx = o.getMatrix(props.matrix); - do { - props.prepend(o.visible, o.alpha, o.shadow, o.compositeOperation); - - // we do this to avoid problems with the matrix being used for both operations when o._props.matrix is passed in as the props param. - // this could be simplified (ie. just done as part of the prepend above) if we switched to using a pool. - if (o != this) { mtx.prependMatrix(o.getMatrix(o._props.matrix)); } - } while (o = o.parent); - return props; - }; - - /** - * Tests whether the display object intersects the specified point in local coordinates (ie. draws a pixel - * with alpha > 0 at the specified position). This ignores the alpha, shadow, hitArea, mask, and compositeOperation - * of the display object. - * - *

Example

- * - * var myShape = new createjs.Shape(); - * myShape.graphics.beginFill("red").drawRect(100, 100, 20, 50); - * - * console.log(myShape.hitTest(10,10); // false - * console.log(myShape.hitTest(110, 25); // true - * - * Note that to use Stage coordinates (such as {{#crossLink "Stage/mouseX:property"}}{{/crossLink}}), they must - * first be converted to local coordinates: - * - * stage.addEventListener("stagemousedown", handleMouseDown); - * function handleMouseDown(event) { - * var p = myShape.globalToLocal(stage.mouseX, stage.mouseY); - * var hit = myShape.hitTest(p.x, p.y); - * } - * - * Shape-to-shape collision is not currently supported by EaselJS. - * - * @method hitTest - * @param {Number} x The x position to check in the display object's local coordinates. - * @param {Number} y The y position to check in the display object's local coordinates. - * @return {Boolean} A Boolean indicating whether a visible portion of the DisplayObject intersect the specified - * local Point. - */ - p.hitTest = function(x, y) { - var ctx = DisplayObject._hitTestContext; - ctx.setTransform(1, 0, 0, 1, -x, -y); - this.draw(ctx); - - var hit = this._testHit(ctx); - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.clearRect(0, 0, 2, 2); - return hit; - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

Example

- * - * var myGraphics = new createjs.Graphics().beginFill("#ff0000").drawCircle(0, 0, 25); - * var shape = stage.addChild(new createjs.Shape()).set({graphics:myGraphics, x:100, y:100, alpha:0.5}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the DisplayObject instance. - * @return {DisplayObject} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - /** - * Returns a rectangle representing this object's bounds in its local coordinate system (ie. with no transformation). - * Objects that have been cached will return the bounds of the cache. - * - * Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use - * {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container - * bounds. - * - * - * - * - * - * - * - * - * - *
All - * All display objects support setting bounds manually using setBounds(). Likewise, display objects that - * have been cached using cache() will return the bounds of their cache. Manual and cache bounds will override - * the automatic calculations listed below. - *
Bitmap - * Returns the width and height of the sourceRect (if specified) or image, extending from (x=0,y=0). - *
Sprite - * Returns the bounds of the current frame. May have non-zero x/y if a frame registration point was specified - * in the spritesheet data. See also {{#crossLink "SpriteSheet/getFrameBounds"}}{{/crossLink}} - *
Container - * Returns the aggregate (combined) bounds of all children that return a non-null value from getBounds(). - *
Shape - * Does not currently support automatic bounds calculations. Use setBounds() to manually define bounds. - *
Text - * Returns approximate bounds. Horizontal values (x/width) are quite accurate, but vertical values (y/height) are - * not, especially when using textBaseline values other than "top". - *
BitmapText - * Returns approximate bounds. Values will be more accurate if spritesheet frame registration points are close - * to (x=0,y=0). - *
- * - * Bounds can be expensive to calculate for some objects (ex. text, or containers with many children), and - * are recalculated each time you call getBounds(). You can prevent recalculation on static objects by setting the - * bounds explicitly: - * - * var bounds = obj.getBounds(); - * obj.setBounds(bounds.x, bounds.y, bounds.width, bounds.height); - * // getBounds will now use the set values, instead of recalculating - * - * To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its - * values if you need to retain it. - * - * var myBounds = obj.getBounds().clone(); - * // OR: - * myRect.copy(obj.getBounds()); - * - * @method getBounds - * @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this - * object. - **/ - p.getBounds = function() { - if (this._bounds) { return this._rectangle.copy(this._bounds); } - var cacheCanvas = this.cacheCanvas; - if (cacheCanvas) { - var scale = this._cacheScale; - return this._rectangle.setValues(this._cacheOffsetX, this._cacheOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale); - } - return null; - }; - - /** - * Returns a rectangle representing this object's bounds in its parent's coordinate system (ie. with transformations applied). - * Objects that have been cached will return the transformed bounds of the cache. - * - * Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use - * {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container - * bounds. - * - * To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its - * values if you need to retain it. - * - * Container instances calculate aggregate bounds for all children that return bounds via getBounds. - * @method getTransformedBounds - * @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this object. - **/ - p.getTransformedBounds = function() { - return this._getBounds(); - }; - - /** - * Allows you to manually specify the bounds of an object that either cannot calculate their own bounds (ex. Shape & - * Text) for future reference, or so the object can be included in Container bounds. Manually set bounds will always - * override calculated bounds. - * - * The bounds should be specified in the object's local (untransformed) coordinates. For example, a Shape instance - * with a 25px radius circle centered at 0,0 would have bounds of (-25, -25, 50, 50). - * @method setBounds - * @param {Number} x The x origin of the bounds. Pass null to remove the manual bounds. - * @param {Number} y The y origin of the bounds. - * @param {Number} width The width of the bounds. - * @param {Number} height The height of the bounds. - **/ - p.setBounds = function(x, y, width, height) { - if (x == null) { this._bounds = x; } - this._bounds = (this._bounds || new createjs.Rectangle()).setValues(x, y, width, height); - }; - - /** - * Returns a clone of this DisplayObject. Some properties that are specific to this instance's current context are - * reverted to their defaults (for example .parent). Caches are not maintained across clones, and some elements - * are copied by reference (masks, individual filter instances, hit area) - * @method clone - * @return {DisplayObject} A clone of the current DisplayObject instance. - **/ - p.clone = function() { - return this._cloneProps(new DisplayObject()); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[DisplayObject (name="+ this.name +")]"; - }; - - -// private methods: - // separated so it can be used more easily in subclasses: - /** - * @method _cloneProps - * @param {DisplayObject} o The DisplayObject instance which will have properties from the current DisplayObject - * instance copied into. - * @return {DisplayObject} o - * @protected - **/ - p._cloneProps = function(o) { - o.alpha = this.alpha; - o.mouseEnabled = this.mouseEnabled; - o.tickEnabled = this.tickEnabled; - o.name = this.name; - o.regX = this.regX; - o.regY = this.regY; - o.rotation = this.rotation; - o.scaleX = this.scaleX; - o.scaleY = this.scaleY; - o.shadow = this.shadow; - o.skewX = this.skewX; - o.skewY = this.skewY; - o.visible = this.visible; - o.x = this.x; - o.y = this.y; - o.compositeOperation = this.compositeOperation; - o.snapToPixel = this.snapToPixel; - o.filters = this.filters==null?null:this.filters.slice(0); - o.mask = this.mask; - o.hitArea = this.hitArea; - o.cursor = this.cursor; - o._bounds = this._bounds; - return o; - }; - - /** - * @method _applyShadow - * @protected - * @param {CanvasRenderingContext2D} ctx - * @param {Shadow} shadow - **/ - p._applyShadow = function(ctx, shadow) { - shadow = shadow || Shadow.identity; - ctx.shadowColor = shadow.color; - ctx.shadowOffsetX = shadow.offsetX; - ctx.shadowOffsetY = shadow.offsetY; - ctx.shadowBlur = shadow.blur; - }; - - - /** - * @method _tick - * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs. - * @protected - **/ - p._tick = function(evtObj) { - // because tick can be really performance sensitive, check for listeners before calling dispatchEvent. - var ls = this._listeners; - if (ls && ls["tick"]) { - // reset & reuse the event object to avoid construction / GC costs: - evtObj.target = null; - evtObj.propagationStopped = evtObj.immediatePropagationStopped = false; - this.dispatchEvent(evtObj); - } - }; - - /** - * @method _testHit - * @protected - * @param {CanvasRenderingContext2D} ctx - * @return {Boolean} - **/ - p._testHit = function(ctx) { - try { - var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1; - } catch (e) { - if (!DisplayObject.suppressCrossDomainErrors) { - throw "An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images."; - } - } - return hit; - }; - - /** - * @method _applyFilters - * @protected - **/ - p._applyFilters = function() { - if (!this.filters || this.filters.length == 0 || !this.cacheCanvas) { return; } - var l = this.filters.length; - var ctx = this.cacheCanvas.getContext("2d"); - var w = this.cacheCanvas.width; - var h = this.cacheCanvas.height; - for (var i=0; i maxX) { maxX = x; } - if ((x = x_a + y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; } - if ((x = y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; } - - if ((y = x_b + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } - if ((y = x_b + y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } - if ((y = y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; } - - return bounds.setValues(minX, minY, maxX-minX, maxY-minY); - }; - - /** - * Indicates whether the display object has any mouse event listeners or a cursor. - * @method _isMouseOpaque - * @return {Boolean} - * @protected - **/ - p._hasMouseEventListener = function() { - var evts = DisplayObject._MOUSE_EVENTS; - for (var i= 0, l=evts.length; itransform and alpha properties concatenated with their parent - * Container. - * - * For example, a {{#crossLink "Shape"}}{{/crossLink}} with x=100 and alpha=0.5, placed in a Container with x=50 - * and alpha=0.7 will be rendered to the canvas at x=150 and alpha=0.35. - * Containers have some overhead, so you generally shouldn't create a Container to hold a single child. - * - *

Example

- * - * var container = new createjs.Container(); - * container.addChild(bitmapInstance, shapeInstance); - * container.x = 100; - * - * @class Container - * @extends DisplayObject - * @constructor - **/ - function Container() { - this.DisplayObject_constructor(); - - // public properties: - /** - * The array of children in the display list. You should usually use the child management methods such as - * {{#crossLink "Container/addChild"}}{{/crossLink}}, {{#crossLink "Container/removeChild"}}{{/crossLink}}, - * {{#crossLink "Container/swapChildren"}}{{/crossLink}}, etc, rather than accessing this directly, but it is - * included for advanced uses. - * @property children - * @type Array - * @default null - **/ - this.children = []; - - /** - * Indicates whether the children of this container are independently enabled for mouse/pointer interaction. - * If false, the children will be aggregated under the container - for example, a click on a child shape would - * trigger a click event on the container. - * @property mouseChildren - * @type Boolean - * @default true - **/ - this.mouseChildren = true; - - /** - * If false, the tick will not be propagated to children of this Container. This can provide some performance benefits. - * In addition to preventing the "tick" event from being dispatched, it will also prevent tick related updates - * on some display objects (ex. Sprite & MovieClip frame advancing, DOMElement visibility handling). - * @property tickChildren - * @type Boolean - * @default true - **/ - this.tickChildren = true; - } - var p = createjs.extend(Container, createjs.DisplayObject); - - -// getter / setters: - /** - * Use the {{#crossLink "Container/numChildren:property"}}{{/crossLink}} property instead. - * @method getNumChildren - * @return {Number} - * @deprecated - **/ - p.getNumChildren = function() { - return this.children.length; - }; - - /** - * Returns the number of children in the container. - * @property numChildren - * @type {Number} - * @readonly - **/ - try { - Object.defineProperties(p, { - numChildren: { get: p.getNumChildren } - }); - } catch (e) {} - - -// public methods: - /** - * Constructor alias for backwards compatibility. This method will be removed in future versions. - * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}. - * @method initialize - * @deprecated in favour of `createjs.promote()` - **/ - p.initialize = Container; // TODO: deprecated. - - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var hasContent = this.cacheCanvas || this.children.length; - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; } - - // this ensures we don't have issues with display list changes that occur during a draw: - var list = this.children.slice(); - for (var i=0,l=list.length; iExample - * - * container.addChild(bitmapInstance); - * - * You can also add multiple children at once: - * - * container.addChild(bitmapInstance, shapeInstance, textInstance); - * - * @method addChild - * @param {DisplayObject} child The display object to add. - * @return {DisplayObject} The child that was added, or the last child if multiple children were added. - **/ - p.addChild = function(child) { - if (child == null) { return child; } - var l = arguments.length; - if (l > 1) { - for (var i=0; iExample - * - * addChildAt(child1, index); - * - * You can also add multiple children, such as: - * - * addChildAt(child1, child2, ..., index); - * - * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list, - * you could use: - * - * container.addChildAt(myShape, container.getChildIndex(otherShape)); - * - * This would also bump otherShape's index up by one. Fails silently if the index is out of range. - * - * @method addChildAt - * @param {DisplayObject} child The display object to add. - * @param {Number} index The index to add the child at. - * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added. - **/ - p.addChildAt = function(child, index) { - var l = arguments.length; - var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1] - if (indx < 0 || indx > this.children.length) { return arguments[l-2]; } - if (l > 2) { - for (var i=0; iExample - * - * container.removeChild(child); - * - * You can also remove multiple children: - * - * removeChild(child1, child2, ...); - * - * Returns true if the child (or children) was removed, or false if it was not in the display list. - * @method removeChild - * @param {DisplayObject} child The child to remove. - * @return {Boolean} true if the child (or children) was removed, or false if it was not in the display list. - **/ - p.removeChild = function(child) { - var l = arguments.length; - if (l > 1) { - var good = true; - for (var i=0; iExample - * - * container.removeChildAt(2); - * - * You can also remove multiple children: - * - * container.removeChild(2, 7, ...) - * - * Returns true if the child (or children) was removed, or false if any index was out of range. - * @method removeChildAt - * @param {Number} index The index of the child to remove. - * @return {Boolean} true if the child (or children) was removed, or false if any index was out of range. - **/ - p.removeChildAt = function(index) { - var l = arguments.length; - if (l > 1) { - var a = []; - for (var i=0; i this.children.length-1) { return false; } - var child = this.children[index]; - if (child) { child.parent = null; } - this.children.splice(index, 1); - child.dispatchEvent("removed"); - return true; - }; - - /** - * Removes all children from the display list. - * - *

Example

- * - * container.removeAllChildren(); - * - * @method removeAllChildren - **/ - p.removeAllChildren = function() { - var kids = this.children; - while (kids.length) { this.removeChildAt(0); } - }; - - /** - * Returns the child at the specified index. - * - *

Example

- * - * container.getChildAt(2); - * - * @method getChildAt - * @param {Number} index The index of the child to return. - * @return {DisplayObject} The child at the specified index. Returns null if there is no child at the index. - **/ - p.getChildAt = function(index) { - return this.children[index]; - }; - - /** - * Returns the child with the specified name. - * @method getChildByName - * @param {String} name The name of the child to return. - * @return {DisplayObject} The child with the specified name. - **/ - p.getChildByName = function(name) { - var kids = this.children; - for (var i=0,l=kids.length;iExample: Display children with a higher y in front. - * - * var sortFunction = function(obj1, obj2, options) { - * if (obj1.y > obj2.y) { return 1; } - * if (obj1.y < obj2.y) { return -1; } - * return 0; - * } - * container.sortChildren(sortFunction); - * - * @method sortChildren - * @param {Function} sortFunction the function to use to sort the child list. See JavaScript's Array.sort - * documentation for details. - **/ - p.sortChildren = function(sortFunction) { - this.children.sort(sortFunction); - }; - - /** - * Returns the index of the specified child in the display list, or -1 if it is not in the display list. - * - *

Example

- * - * var index = container.getChildIndex(child); - * - * @method getChildIndex - * @param {DisplayObject} child The child to return the index of. - * @return {Number} The index of the specified child. -1 if the child is not found. - **/ - p.getChildIndex = function(child) { - return createjs.indexOf(this.children, child); - }; - - /** - * Swaps the children at the specified indexes. Fails silently if either index is out of range. - * @method swapChildrenAt - * @param {Number} index1 - * @param {Number} index2 - **/ - p.swapChildrenAt = function(index1, index2) { - var kids = this.children; - var o1 = kids[index1]; - var o2 = kids[index2]; - if (!o1 || !o2) { return; } - kids[index1] = o2; - kids[index2] = o1; - }; - - /** - * Swaps the specified children's depth in the display list. Fails silently if either child is not a child of this - * Container. - * @method swapChildren - * @param {DisplayObject} child1 - * @param {DisplayObject} child2 - **/ - p.swapChildren = function(child1, child2) { - var kids = this.children; - var index1,index2; - for (var i=0,l=kids.length;i= l) { return; } - for (var i=0;i 0 at the - * specified position). This ignores the alpha, shadow and compositeOperation of the display object, and all - * transform properties including regX/Y. - * @method hitTest - * @param {Number} x The x position to check in the display object's local coordinates. - * @param {Number} y The y position to check in the display object's local coordinates. - * @return {Boolean} A Boolean indicating whether there is a visible section of a DisplayObject that overlaps the specified - * coordinates. - **/ - p.hitTest = function(x, y) { - // TODO: optimize to use the fast cache check where possible. - return (this.getObjectUnderPoint(x, y) != null); - }; - - /** - * Returns an array of all display objects under the specified coordinates that are in this container's display - * list. This routine ignores any display objects with {{#crossLink "DisplayObject/mouseEnabled:property"}}{{/crossLink}} - * set to `false`. The array will be sorted in order of visual depth, with the top-most display object at index 0. - * This uses shape based hit detection, and can be an expensive operation to run, so it is best to use it carefully. - * For example, if testing for objects under the mouse, test on tick (instead of on {{#crossLink "DisplayObject/mousemove:event"}}{{/crossLink}}), - * and only if the mouse's position has changed. - * - *
    - *
  • By default (mode=0) this method evaluates all display objects.
  • - *
  • By setting the `mode` parameter to `1`, the {{#crossLink "DisplayObject/mouseEnabled:property"}}{{/crossLink}} - * and {{#crossLink "mouseChildren:property"}}{{/crossLink}} properties will be respected.
  • - *
  • Setting the `mode` to `2` additionally excludes display objects that do not have active mouse event - * listeners or a {{#crossLink "DisplayObject:cursor:property"}}{{/crossLink}} property. That is, only objects - * that would normally intercept mouse interaction will be included. This can significantly improve performance - * in some cases by reducing the number of display objects that need to be tested.
  • - * - * - * This method accounts for both {{#crossLink "DisplayObject/hitArea:property"}}{{/crossLink}} and {{#crossLink "DisplayObject/mask:property"}}{{/crossLink}}. - * @method getObjectsUnderPoint - * @param {Number} x The x position in the container to test. - * @param {Number} y The y position in the container to test. - * @param {Number} [mode=0] The mode to use to determine which display objects to include. 0-all, 1-respect mouseEnabled/mouseChildren, 2-only mouse opaque objects. - * @return {Array} An Array of DisplayObjects under the specified coordinates. - **/ - p.getObjectsUnderPoint = function(x, y, mode) { - var arr = []; - var pt = this.localToGlobal(x, y); - this._getObjectsUnderPoint(pt.x, pt.y, arr, mode>0, mode==1); - return arr; - }; - - /** - * Similar to {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}, but returns only the top-most display - * object. This runs significantly faster than getObjectsUnderPoint(), but is still potentially an expensive - * operation. See {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}} for more information. - * @method getObjectUnderPoint - * @param {Number} x The x position in the container to test. - * @param {Number} y The y position in the container to test. - * @param {Number} mode The mode to use to determine which display objects to include. 0-all, 1-respect mouseEnabled/mouseChildren, 2-only mouse opaque objects. - * @return {DisplayObject} The top-most display object under the specified coordinates. - **/ - p.getObjectUnderPoint = function(x, y, mode) { - var pt = this.localToGlobal(x, y); - return this._getObjectsUnderPoint(pt.x, pt.y, null, mode>0, mode==1); - }; - - /** - * Docced in superclass. - */ - p.getBounds = function() { - return this._getBounds(null, true); - }; - - - /** - * Docced in superclass. - */ - p.getTransformedBounds = function() { - return this._getBounds(); - }; - - /** - * Returns a clone of this Container. Some properties that are specific to this instance's current context are - * reverted to their defaults (for example .parent). - * @method clone - * @param {Boolean} [recursive=false] If true, all of the descendants of this container will be cloned recursively. If false, the - * properties of the container will be cloned, but the new instance will not have any children. - * @return {Container} A clone of the current Container instance. - **/ - p.clone = function(recursive) { - var o = this._cloneProps(new Container()); - if (recursive) { this._cloneChildren(o); } - return o; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Container (name="+ this.name +")]"; - }; - - -// private methods: - /** - * @method _tick - * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs. - * @protected - **/ - p._tick = function(evtObj) { - if (this.tickChildren) { - for (var i=this.children.length-1; i>=0; i--) { - var child = this.children[i]; - if (child.tickEnabled && child._tick) { child._tick(evtObj); } - } - } - this.DisplayObject__tick(evtObj); - }; - - /** - * Recursively clones all children of this container, and adds them to the target container. - * @method cloneChildren - * @protected - * @param {Container} o The target container. - **/ - p._cloneChildren = function(o) { - if (o.children.length) { o.removeAllChildren(); } - var arr = o.children; - for (var i=0, l=this.children.length; i=0; i--) { - var child = children[i]; - var hitArea = child.hitArea; - if (!child.visible || (!hitArea && !child.isVisible()) || (mouse && !child.mouseEnabled)) { continue; } - if (!hitArea && !this._testMask(child, x, y)) { continue; } - - // if a child container has a hitArea then we only need to check its hitArea, so we can treat it as a normal DO: - if (!hitArea && child instanceof Container) { - var result = child._getObjectsUnderPoint(x, y, arr, mouse, activeListener, currentDepth+1); - if (!arr && result) { return (mouse && !this.mouseChildren) ? this : result; } - } else { - if (mouse && !activeListener && !child._hasMouseEventListener()) { continue; } - - // TODO: can we pass displayProps forward, to avoid having to calculate this backwards every time? It's kind of a mixed bag. When we're only hunting for DOs with event listeners, it may not make sense. - var props = child.getConcatenatedDisplayProps(child._props); - mtx = props.matrix; - - if (hitArea) { - mtx.appendMatrix(hitArea.getMatrix(hitArea._props.matrix)); - props.alpha = hitArea.alpha; - } - - ctx.globalAlpha = props.alpha; - ctx.setTransform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx-x, mtx.ty-y); - (hitArea||child).draw(ctx); - if (!this._testHit(ctx)) { continue; } - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.clearRect(0, 0, 2, 2); - if (arr) { arr.push(child); } - else { return (mouse && !this.mouseChildren) ? this : child; } - } - } - return null; - }; - - /** - * @method _testMask - * @param {DisplayObject} target - * @param {Number} x - * @param {Number} y - * @return {Boolean} Indicates whether the x/y is within the masked region. - * @protected - **/ - p._testMask = function(target, x, y) { - var mask = target.mask; - if (!mask || !mask.graphics || mask.graphics.isEmpty()) { return true; } - - var mtx = this._props.matrix, parent = target.parent; - mtx = parent ? parent.getConcatenatedMatrix(mtx) : mtx.identity(); - mtx = mask.getMatrix(mask._props.matrix).prependMatrix(mtx); - - var ctx = createjs.DisplayObject._hitTestContext; - ctx.setTransform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx-x, mtx.ty-y); - - // draw the mask as a solid fill: - mask.graphics.drawAsPath(ctx); - ctx.fillStyle = "#000"; - ctx.fill(); - - if (!this._testHit(ctx)) { return false; } - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.clearRect(0, 0, 2, 2); - - return true; - }; - - /** - * @method _getBounds - * @param {Matrix2D} matrix - * @param {Boolean} ignoreTransform If true, does not apply this object's transform. - * @return {Rectangle} - * @protected - **/ - p._getBounds = function(matrix, ignoreTransform) { - var bounds = this.DisplayObject_getBounds(); - if (bounds) { return this._transformBounds(bounds, matrix, ignoreTransform); } - - var mtx = this._props.matrix; - mtx = ignoreTransform ? mtx.identity() : this.getMatrix(mtx); - if (matrix) { mtx.prependMatrix(matrix); } - - var l = this.children.length, rect=null; - for (var i=0; iExample - * This example creates a stage, adds a child to it, then uses {{#crossLink "Ticker"}}{{/crossLink}} to update the child - * and redraw the stage using {{#crossLink "Stage/update"}}{{/crossLink}}. - * - * var stage = new createjs.Stage("canvasElementId"); - * var image = new createjs.Bitmap("imagePath.png"); - * stage.addChild(image); - * createjs.Ticker.addEventListener("tick", handleTick); - * function handleTick(event) { - * image.x += 10; - * stage.update(); - * } - * - * @class Stage - * @extends Container - * @constructor - * @param {HTMLCanvasElement | String | Object} canvas A canvas object that the Stage will render to, or the string id - * of a canvas object in the current document. - **/ - function Stage(canvas) { - this.Container_constructor(); - - - // public properties: - /** - * Indicates whether the stage should automatically clear the canvas before each render. You can set this to false - * to manually control clearing (for generative art, or when pointing multiple stages at the same canvas for - * example). - * - *

    Example

    - * - * var stage = new createjs.Stage("canvasId"); - * stage.autoClear = false; - * - * @property autoClear - * @type Boolean - * @default true - **/ - this.autoClear = true; - - /** - * The canvas the stage will render to. Multiple stages can share a single canvas, but you must disable autoClear for all but the - * first stage that will be ticked (or they will clear each other's render). - * - * When changing the canvas property you must disable the events on the old canvas, and enable events on the - * new canvas or mouse events will not work as expected. For example: - * - * myStage.enableDOMEvents(false); - * myStage.canvas = anotherCanvas; - * myStage.enableDOMEvents(true); - * - * @property canvas - * @type HTMLCanvasElement | Object - **/ - this.canvas = (typeof canvas == "string") ? document.getElementById(canvas) : canvas; - - /** - * The current mouse X position on the canvas. If the mouse leaves the canvas, this will indicate the most recent - * position over the canvas, and mouseInBounds will be set to false. - * @property mouseX - * @type Number - * @readonly - **/ - this.mouseX = 0; - - /** - * The current mouse Y position on the canvas. If the mouse leaves the canvas, this will indicate the most recent - * position over the canvas, and mouseInBounds will be set to false. - * @property mouseY - * @type Number - * @readonly - **/ - this.mouseY = 0; - - /** - * Specifies the area of the stage to affect when calling update. This can be use to selectively - * re-draw specific regions of the canvas. If null, the whole canvas area is drawn. - * @property drawRect - * @type {Rectangle} - */ - this.drawRect = null; - - /** - * Indicates whether display objects should be rendered on whole pixels. You can set the - * {{#crossLink "DisplayObject/snapToPixel"}}{{/crossLink}} property of - * display objects to false to enable/disable this behaviour on a per instance basis. - * @property snapToPixelEnabled - * @type Boolean - * @default false - **/ - this.snapToPixelEnabled = false; - - /** - * Indicates whether the mouse is currently within the bounds of the canvas. - * @property mouseInBounds - * @type Boolean - * @default false - **/ - this.mouseInBounds = false; - - /** - * If true, tick callbacks will be called on all display objects on the stage prior to rendering to the canvas. - * @property tickOnUpdate - * @type Boolean - * @default true - **/ - this.tickOnUpdate = true; - - /** - * If true, mouse move events will continue to be called when the mouse leaves the target canvas. See - * {{#crossLink "Stage/mouseInBounds:property"}}{{/crossLink}}, and {{#crossLink "MouseEvent"}}{{/crossLink}} - * x/y/rawX/rawY. - * @property mouseMoveOutside - * @type Boolean - * @default false - **/ - this.mouseMoveOutside = false; - - - /** - * Prevents selection of other elements in the html page if the user clicks and drags, or double clicks on the canvas. - * This works by calling `preventDefault()` on any mousedown events (or touch equivalent) originating on the canvas. - * @property preventSelection - * @type Boolean - * @default true - **/ - this.preventSelection = true; - - /** - * The hitArea property is not supported for Stage. - * @property hitArea - * @type {DisplayObject} - * @default null - */ - - - // private properties: - /** - * Holds objects with data for each active pointer id. Each object has the following properties: - * x, y, event, target, overTarget, overX, overY, inBounds, posEvtObj (native event that last updated position) - * @property _pointerData - * @type {Object} - * @private - */ - this._pointerData = {}; - - /** - * Number of active pointers. - * @property _pointerCount - * @type {Object} - * @private - */ - this._pointerCount = 0; - - /** - * The ID of the primary pointer. - * @property _primaryPointerID - * @type {Object} - * @private - */ - this._primaryPointerID = null; - - /** - * @property _mouseOverIntervalID - * @protected - * @type Number - **/ - this._mouseOverIntervalID = null; - - /** - * @property _nextStage - * @protected - * @type Stage - **/ - this._nextStage = null; - - /** - * @property _prevStage - * @protected - * @type Stage - **/ - this._prevStage = null; - - - // initialize: - this.enableDOMEvents(true); - } - var p = createjs.extend(Stage, createjs.Container); - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// events: - /** - * Dispatched when the user moves the mouse over the canvas. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event stagemousemove - * @since 0.6.0 - */ - - /** - * Dispatched when the user presses their left mouse button on the canvas. See the {{#crossLink "MouseEvent"}}{{/crossLink}} - * class for a listing of event properties. - * @event stagemousedown - * @since 0.6.0 - */ - - /** - * Dispatched when the user the user presses somewhere on the stage, then releases the mouse button anywhere that the page can detect it (this varies slightly between browsers). - * You can use {{#crossLink "Stage/mouseInBounds:property"}}{{/crossLink}} to check whether the mouse is currently within the stage bounds. - * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties. - * @event stagemouseup - * @since 0.6.0 - */ - - /** - * Dispatched when the mouse moves from within the canvas area (mouseInBounds == true) to outside it (mouseInBounds == false). - * This is currently only dispatched for mouse input (not touch). See the {{#crossLink "MouseEvent"}}{{/crossLink}} - * class for a listing of event properties. - * @event mouseleave - * @since 0.7.0 - */ - - /** - * Dispatched when the mouse moves into the canvas area (mouseInBounds == false) from outside it (mouseInBounds == true). - * This is currently only dispatched for mouse input (not touch). See the {{#crossLink "MouseEvent"}}{{/crossLink}} - * class for a listing of event properties. - * @event mouseenter - * @since 0.7.0 - */ - - /** - * Dispatched each update immediately before the tick event is propagated through the display list. - * You can call preventDefault on the event object to cancel propagating the tick event. - * @event tickstart - * @since 0.7.0 - */ - - /** - * Dispatched each update immediately after the tick event is propagated through the display list. Does not fire if - * tickOnUpdate is false. Precedes the "drawstart" event. - * @event tickend - * @since 0.7.0 - */ - - /** - * Dispatched each update immediately before the canvas is cleared and the display list is drawn to it. - * You can call preventDefault on the event object to cancel the draw. - * @event drawstart - * @since 0.7.0 - */ - - /** - * Dispatched each update immediately after the display list is drawn to the canvas and the canvas context is restored. - * @event drawend - * @since 0.7.0 - */ - - -// getter / setters: - /** - * Specifies a target stage that will have mouse / touch interactions relayed to it after this stage handles them. - * This can be useful in cases where you have multiple layered canvases and want user interactions - * events to pass through. For example, this would relay mouse events from topStage to bottomStage: - * - * topStage.nextStage = bottomStage; - * - * To disable relaying, set nextStage to null. - * - * MouseOver, MouseOut, RollOver, and RollOut interactions are also passed through using the mouse over settings - * of the top-most stage, but are only processed if the target stage has mouse over interactions enabled. - * Considerations when using roll over in relay targets:
      - *
    1. The top-most (first) stage must have mouse over interactions enabled (via enableMouseOver)
    2. - *
    3. All stages that wish to participate in mouse over interaction must enable them via enableMouseOver
    4. - *
    5. All relay targets will share the frequency value of the top-most stage
    6. - *
    - * To illustrate, in this example the targetStage would process mouse over interactions at 10hz (despite passing - * 30 as it's desired frequency): - * topStage.nextStage = targetStage; - * topStage.enableMouseOver(10); - * targetStage.enableMouseOver(30); - * - * If the target stage's canvas is completely covered by this stage's canvas, you may also want to disable its - * DOM events using: - * - * targetStage.enableDOMEvents(false); - * - * @property nextStage - * @type {Stage} - **/ - p._get_nextStage = function() { - return this._nextStage; - }; - p._set_nextStage = function(value) { - if (this._nextStage) { this._nextStage._prevStage = null; } - if (value) { value._prevStage = this; } - this._nextStage = value; - }; - - try { - Object.defineProperties(p, { - nextStage: { get: p._get_nextStage, set: p._set_nextStage } - }); - } catch (e) {} // TODO: use Log - - -// public methods: - /** - * Each time the update method is called, the stage will call {{#crossLink "Stage/tick"}}{{/crossLink}} - * unless {{#crossLink "Stage/tickOnUpdate:property"}}{{/crossLink}} is set to false, - * and then render the display list to the canvas. - * - * @method update - * @param {Object} [props] Props object to pass to `tick()`. Should usually be a {{#crossLink "Ticker"}}{{/crossLink}} event object, or similar object with a delta property. - **/ - p.update = function(props) { - if (!this.canvas) { return; } - if (this.tickOnUpdate) { this.tick(props); } - if (this.dispatchEvent("drawstart", false, true) === false) { return; } - createjs.DisplayObject._snapToPixelEnabled = this.snapToPixelEnabled; - var r = this.drawRect, ctx = this.canvas.getContext("2d"); - ctx.setTransform(1, 0, 0, 1, 0, 0); - if (this.autoClear) { - if (r) { ctx.clearRect(r.x, r.y, r.width, r.height); } - else { ctx.clearRect(0, 0, this.canvas.width+1, this.canvas.height+1); } - } - ctx.save(); - if (this.drawRect) { - ctx.beginPath(); - ctx.rect(r.x, r.y, r.width, r.height); - ctx.clip(); - } - this.updateContext(ctx); - this.draw(ctx, false); - ctx.restore(); - this.dispatchEvent("drawend"); - }; - - /** - * Propagates a tick event through the display list. This is automatically called by {{#crossLink "Stage/update"}}{{/crossLink}} - * unless {{#crossLink "Stage/tickOnUpdate:property"}}{{/crossLink}} is set to false. - * - * If a props object is passed to `tick()`, then all of its properties will be copied to the event object that is - * propagated to listeners. - * - * Some time-based features in EaselJS (for example {{#crossLink "Sprite/framerate"}}{{/crossLink}} require that - * a {{#crossLink "Ticker/tick:event"}}{{/crossLink}} event object (or equivalent object with a delta property) be - * passed as the `props` parameter to `tick()`. For example: - * - * Ticker.on("tick", handleTick); - * function handleTick(evtObj) { - * // clone the event object from Ticker, and add some custom data to it: - * var evt = evtObj.clone().set({greeting:"hello", name:"world"}); - * - * // pass it to stage.update(): - * myStage.update(evt); // subsequently calls tick() with the same param - * } - * - * // ... - * myDisplayObject.on("tick", handleDisplayObjectTick); - * function handleDisplayObjectTick(evt) { - * console.log(evt.delta); // the delta property from the Ticker tick event object - * console.log(evt.greeting, evt.name); // custom data: "hello world" - * } - * - * @method tick - * @param {Object} [props] An object with properties that should be copied to the event object. Should usually be a Ticker event object, or similar object with a delta property. - **/ - p.tick = function(props) { - if (!this.tickEnabled || this.dispatchEvent("tickstart", false, true) === false) { return; } - var evtObj = new createjs.Event("tick"); - if (props) { - for (var n in props) { - if (props.hasOwnProperty(n)) { evtObj[n] = props[n]; } - } - } - this._tick(evtObj); - this.dispatchEvent("tickend"); - }; - - /** - * Default event handler that calls the Stage {{#crossLink "Stage/update"}}{{/crossLink}} method when a {{#crossLink "DisplayObject/tick:event"}}{{/crossLink}} - * event is received. This allows you to register a Stage instance as a event listener on {{#crossLink "Ticker"}}{{/crossLink}} - * directly, using: - * - * Ticker.addEventListener("tick", myStage"); - * - * Note that if you subscribe to ticks using this pattern, then the tick event object will be passed through to - * display object tick handlers, instead of delta and paused parameters. - * @property handleEvent - * @type Function - **/ - p.handleEvent = function(evt) { - if (evt.type == "tick") { this.update(evt); } - }; - - /** - * Clears the target canvas. Useful if {{#crossLink "Stage/autoClear:property"}}{{/crossLink}} is set to `false`. - * @method clear - **/ - p.clear = function() { - if (!this.canvas) { return; } - var ctx = this.canvas.getContext("2d"); - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.clearRect(0, 0, this.canvas.width+1, this.canvas.height+1); - }; - - /** - * Returns a data url that contains a Base64-encoded image of the contents of the stage. The returned data url can - * be specified as the src value of an image element. - * @method toDataURL - * @param {String} [backgroundColor] The background color to be used for the generated image. Any valid CSS color - * value is allowed. The default value is a transparent background. - * @param {String} [mimeType="image/png"] The MIME type of the image format to be create. The default is "image/png". If an unknown MIME type - * is passed in, or if the browser does not support the specified MIME type, the default value will be used. - * @return {String} a Base64 encoded image. - **/ - p.toDataURL = function(backgroundColor, mimeType) { - var data, ctx = this.canvas.getContext('2d'), w = this.canvas.width, h = this.canvas.height; - - if (backgroundColor) { - data = ctx.getImageData(0, 0, w, h); - var compositeOperation = ctx.globalCompositeOperation; - ctx.globalCompositeOperation = "destination-over"; - - ctx.fillStyle = backgroundColor; - ctx.fillRect(0, 0, w, h); - } - - var dataURL = this.canvas.toDataURL(mimeType||"image/png"); - - if(backgroundColor) { - ctx.putImageData(data, 0, 0); - ctx.globalCompositeOperation = compositeOperation; - } - - return dataURL; - }; - - /** - * Enables or disables (by passing a frequency of 0) mouse over ({{#crossLink "DisplayObject/mouseover:event"}}{{/crossLink}} - * and {{#crossLink "DisplayObject/mouseout:event"}}{{/crossLink}}) and roll over events ({{#crossLink "DisplayObject/rollover:event"}}{{/crossLink}} - * and {{#crossLink "DisplayObject/rollout:event"}}{{/crossLink}}) for this stage's display list. These events can - * be expensive to generate, so they are disabled by default. The frequency of the events can be controlled - * independently of mouse move events via the optional `frequency` parameter. - * - *

    Example

    - * - * var stage = new createjs.Stage("canvasId"); - * stage.enableMouseOver(10); // 10 updates per second - * - * @method enableMouseOver - * @param {Number} [frequency=20] Optional param specifying the maximum number of times per second to broadcast - * mouse over/out events. Set to 0 to disable mouse over events completely. Maximum is 50. A lower frequency is less - * responsive, but uses less CPU. - **/ - p.enableMouseOver = function(frequency) { - if (this._mouseOverIntervalID) { - clearInterval(this._mouseOverIntervalID); - this._mouseOverIntervalID = null; - if (frequency == 0) { - this._testMouseOver(true); - } - } - if (frequency == null) { frequency = 20; } - else if (frequency <= 0) { return; } - var o = this; - this._mouseOverIntervalID = setInterval(function(){ o._testMouseOver(); }, 1000/Math.min(50,frequency)); - }; - - /** - * Enables or disables the event listeners that stage adds to DOM elements (window, document and canvas). It is good - * practice to disable events when disposing of a Stage instance, otherwise the stage will continue to receive - * events from the page. - * - * When changing the canvas property you must disable the events on the old canvas, and enable events on the - * new canvas or mouse events will not work as expected. For example: - * - * myStage.enableDOMEvents(false); - * myStage.canvas = anotherCanvas; - * myStage.enableDOMEvents(true); - * - * @method enableDOMEvents - * @param {Boolean} [enable=true] Indicates whether to enable or disable the events. Default is true. - **/ - p.enableDOMEvents = function(enable) { - if (enable == null) { enable = true; } - var n, o, ls = this._eventListeners; - if (!enable && ls) { - for (n in ls) { - o = ls[n]; - o.t.removeEventListener(n, o.f, false); - } - this._eventListeners = null; - } else if (enable && !ls && this.canvas) { - var t = window.addEventListener ? window : document; - var _this = this; - ls = this._eventListeners = {}; - ls["mouseup"] = {t:t, f:function(e) { _this._handleMouseUp(e)} }; - ls["mousemove"] = {t:t, f:function(e) { _this._handleMouseMove(e)} }; - ls["dblclick"] = {t:this.canvas, f:function(e) { _this._handleDoubleClick(e)} }; - ls["mousedown"] = {t:this.canvas, f:function(e) { _this._handleMouseDown(e)} }; - - for (n in ls) { - o = ls[n]; - o.t.addEventListener(n, o.f, false); - } - } - }; - - /** - * Stage instances cannot be cloned. - * @method clone - **/ - p.clone = function() { - throw("Stage cannot be cloned."); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Stage (name="+ this.name +")]"; - }; - - -// private methods: - /** - * @method _getElementRect - * @protected - * @param {HTMLElement} e - **/ - p._getElementRect = function(e) { - var bounds; - try { bounds = e.getBoundingClientRect(); } // this can fail on disconnected DOM elements in IE9 - catch (err) { bounds = {top: e.offsetTop, left: e.offsetLeft, width:e.offsetWidth, height:e.offsetHeight}; } - - var offX = (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || document.body.clientLeft || 0); - var offY = (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || document.body.clientTop || 0); - - var styles = window.getComputedStyle ? getComputedStyle(e,null) : e.currentStyle; // IE <9 compatibility. - var padL = parseInt(styles.paddingLeft)+parseInt(styles.borderLeftWidth); - var padT = parseInt(styles.paddingTop)+parseInt(styles.borderTopWidth); - var padR = parseInt(styles.paddingRight)+parseInt(styles.borderRightWidth); - var padB = parseInt(styles.paddingBottom)+parseInt(styles.borderBottomWidth); - - // note: in some browsers bounds properties are read only. - return { - left: bounds.left+offX+padL, - right: bounds.right+offX-padR, - top: bounds.top+offY+padT, - bottom: bounds.bottom+offY-padB - } - }; - - /** - * @method _getPointerData - * @protected - * @param {Number} id - **/ - p._getPointerData = function(id) { - var data = this._pointerData[id]; - if (!data) { data = this._pointerData[id] = {x:0,y:0}; } - return data; - }; - - /** - * @method _handleMouseMove - * @protected - * @param {MouseEvent} e - **/ - p._handleMouseMove = function(e) { - if(!e){ e = window.event; } - this._handlePointerMove(-1, e, e.pageX, e.pageY); - }; - - /** - * @method _handlePointerMove - * @protected - * @param {Number} id - * @param {Event} e - * @param {Number} pageX - * @param {Number} pageY - * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage. - **/ - p._handlePointerMove = function(id, e, pageX, pageY, owner) { - if (this._prevStage && owner === undefined) { return; } // redundant listener. - if (!this.canvas) { return; } - var nextStage=this._nextStage, o=this._getPointerData(id); - - var inBounds = o.inBounds; - this._updatePointerPosition(id, e, pageX, pageY); - if (inBounds || o.inBounds || this.mouseMoveOutside) { - if (id === -1 && o.inBounds == !inBounds) { - this._dispatchMouseEvent(this, (inBounds ? "mouseleave" : "mouseenter"), false, id, o, e); - } - - this._dispatchMouseEvent(this, "stagemousemove", false, id, o, e); - this._dispatchMouseEvent(o.target, "pressmove", true, id, o, e); - } - - nextStage&&nextStage._handlePointerMove(id, e, pageX, pageY, null); - }; - - /** - * @method _updatePointerPosition - * @protected - * @param {Number} id - * @param {Event} e - * @param {Number} pageX - * @param {Number} pageY - **/ - p._updatePointerPosition = function(id, e, pageX, pageY) { - var rect = this._getElementRect(this.canvas); - pageX -= rect.left; - pageY -= rect.top; - - var w = this.canvas.width; - var h = this.canvas.height; - pageX /= (rect.right-rect.left)/w; - pageY /= (rect.bottom-rect.top)/h; - var o = this._getPointerData(id); - if (o.inBounds = (pageX >= 0 && pageY >= 0 && pageX <= w-1 && pageY <= h-1)) { - o.x = pageX; - o.y = pageY; - } else if (this.mouseMoveOutside) { - o.x = pageX < 0 ? 0 : (pageX > w-1 ? w-1 : pageX); - o.y = pageY < 0 ? 0 : (pageY > h-1 ? h-1 : pageY); - } - - o.posEvtObj = e; - o.rawX = pageX; - o.rawY = pageY; - - if (id === this._primaryPointerID || id === -1) { - this.mouseX = o.x; - this.mouseY = o.y; - this.mouseInBounds = o.inBounds; - } - }; - - /** - * @method _handleMouseUp - * @protected - * @param {MouseEvent} e - **/ - p._handleMouseUp = function(e) { - this._handlePointerUp(-1, e, false); - }; - - /** - * @method _handlePointerUp - * @protected - * @param {Number} id - * @param {Event} e - * @param {Boolean} clear - * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage. - **/ - p._handlePointerUp = function(id, e, clear, owner) { - var nextStage = this._nextStage, o = this._getPointerData(id); - if (this._prevStage && owner === undefined) { return; } // redundant listener. - - var target=null, oTarget = o.target; - if (!owner && (oTarget || nextStage)) { target = this._getObjectsUnderPoint(o.x, o.y, null, true); } - - if (o.down) { this._dispatchMouseEvent(this, "stagemouseup", false, id, o, e, target); o.down = false; } - - if (target == oTarget) { this._dispatchMouseEvent(oTarget, "click", true, id, o, e); } - this._dispatchMouseEvent(oTarget, "pressup", true, id, o, e); - - if (clear) { - if (id==this._primaryPointerID) { this._primaryPointerID = null; } - delete(this._pointerData[id]); - } else { o.target = null; } - - nextStage&&nextStage._handlePointerUp(id, e, clear, owner || target && this); - }; - - /** - * @method _handleMouseDown - * @protected - * @param {MouseEvent} e - **/ - p._handleMouseDown = function(e) { - this._handlePointerDown(-1, e, e.pageX, e.pageY); - }; - - /** - * @method _handlePointerDown - * @protected - * @param {Number} id - * @param {Event} e - * @param {Number} pageX - * @param {Number} pageY - * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage. - **/ - p._handlePointerDown = function(id, e, pageX, pageY, owner) { - if (this.preventSelection) { e.preventDefault(); } - if (this._primaryPointerID == null || id === -1) { this._primaryPointerID = id; } // mouse always takes over. - - if (pageY != null) { this._updatePointerPosition(id, e, pageX, pageY); } - var target = null, nextStage = this._nextStage, o = this._getPointerData(id); - if (!owner) { target = o.target = this._getObjectsUnderPoint(o.x, o.y, null, true); } - - if (o.inBounds) { this._dispatchMouseEvent(this, "stagemousedown", false, id, o, e, target); o.down = true; } - this._dispatchMouseEvent(target, "mousedown", true, id, o, e); - - nextStage&&nextStage._handlePointerDown(id, e, pageX, pageY, owner || target && this); - }; - - /** - * @method _testMouseOver - * @param {Boolean} clear If true, clears the mouseover / rollover (ie. no target) - * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage. - * @param {Stage} eventTarget The stage that the cursor is actively over. - * @protected - **/ - p._testMouseOver = function(clear, owner, eventTarget) { - if (this._prevStage && owner === undefined) { return; } // redundant listener. - - var nextStage = this._nextStage; - if (!this._mouseOverIntervalID) { - // not enabled for mouseover, but should still relay the event. - nextStage&&nextStage._testMouseOver(clear, owner, eventTarget); - return; - } - var o = this._getPointerData(-1); - // only update if the mouse position has changed. This provides a lot of optimization, but has some trade-offs. - if (!o || (!clear && this.mouseX == this._mouseOverX && this.mouseY == this._mouseOverY && this.mouseInBounds)) { return; } - - var e = o.posEvtObj; - var isEventTarget = eventTarget || e&&(e.target == this.canvas); - var target=null, common = -1, cursor="", t, i, l; - - if (!owner && (clear || this.mouseInBounds && isEventTarget)) { - target = this._getObjectsUnderPoint(this.mouseX, this.mouseY, null, true); - this._mouseOverX = this.mouseX; - this._mouseOverY = this.mouseY; - } - - var oldList = this._mouseOverTarget||[]; - var oldTarget = oldList[oldList.length-1]; - var list = this._mouseOverTarget = []; - - // generate ancestor list and check for cursor: - t = target; - while (t) { - list.unshift(t); - if (!cursor) { cursor = t.cursor; } - t = t.parent; - } - this.canvas.style.cursor = cursor; - if (!owner && eventTarget) { eventTarget.canvas.style.cursor = cursor; } - - // find common ancestor: - for (i=0,l=list.length; icommon; i--) { - this._dispatchMouseEvent(oldList[i], "rollout", false, -1, o, e, target); - } - - for (i=list.length-1; i>common; i--) { - this._dispatchMouseEvent(list[i], "rollover", false, -1, o, e, oldTarget); - } - - if (oldTarget != target) { - this._dispatchMouseEvent(target, "mouseover", true, -1, o, e, oldTarget); - } - - nextStage&&nextStage._testMouseOver(clear, owner || target && this, eventTarget || isEventTarget && this); - }; - - /** - * @method _handleDoubleClick - * @protected - * @param {MouseEvent} e - * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage. - **/ - p._handleDoubleClick = function(e, owner) { - var target=null, nextStage=this._nextStage, o=this._getPointerData(-1); - if (!owner) { - target = this._getObjectsUnderPoint(o.x, o.y, null, true); - this._dispatchMouseEvent(target, "dblclick", true, -1, o, e); - } - nextStage&&nextStage._handleDoubleClick(e, owner || target && this); - }; - - /** - * @method _dispatchMouseEvent - * @protected - * @param {DisplayObject} target - * @param {String} type - * @param {Boolean} bubbles - * @param {Number} pointerId - * @param {Object} o - * @param {MouseEvent} [nativeEvent] - * @param {DisplayObject} [relatedTarget] - **/ - p._dispatchMouseEvent = function(target, type, bubbles, pointerId, o, nativeEvent, relatedTarget) { - // TODO: might be worth either reusing MouseEvent instances, or adding a willTrigger method to avoid GC. - if (!target || (!bubbles && !target.hasEventListener(type))) { return; } - /* - // TODO: account for stage transformations? - this._mtx = this.getConcatenatedMatrix(this._mtx).invert(); - var pt = this._mtx.transformPoint(o.x, o.y); - var evt = new createjs.MouseEvent(type, bubbles, false, pt.x, pt.y, nativeEvent, pointerId, pointerId==this._primaryPointerID || pointerId==-1, o.rawX, o.rawY); - */ - var evt = new createjs.MouseEvent(type, bubbles, false, o.x, o.y, nativeEvent, pointerId, pointerId === this._primaryPointerID || pointerId === -1, o.rawX, o.rawY, relatedTarget); - target.dispatchEvent(evt); - }; - - - createjs.Stage = createjs.promote(Stage, "Container"); -}()); - -//############################################################################## -// Bitmap.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - - /** - * A Bitmap represents an Image, Canvas, or Video in the display list. A Bitmap can be instantiated using an existing - * HTML element, or a string. - * - *

    Example

    - * - * var bitmap = new createjs.Bitmap("imagePath.jpg"); - * - * Notes: - *
      - *
    1. When a string path or image tag that is not yet loaded is used, the stage may need to be redrawn before it - * will be displayed.
    2. - *
    3. Bitmaps with an SVG source currently will not respect an alpha value other than 0 or 1. To get around this, - * the Bitmap can be cached.
    4. - *
    5. Bitmaps with an SVG source will taint the canvas with cross-origin data, which prevents interactivity. This - * happens in all browsers except recent Firefox builds.
    6. - *
    7. Images loaded cross-origin will throw cross-origin security errors when interacted with using a mouse, using - * methods such as `getObjectUnderPoint`, or using filters, or caching. You can get around this by setting - * `crossOrigin` flags on your images before passing them to EaselJS, eg: `img.crossOrigin="Anonymous";`
    8. - *
    - * - * @class Bitmap - * @extends DisplayObject - * @constructor - * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | String} imageOrUri The source object or URI to an image to - * display. This can be either an Image, Canvas, or Video object, or a string URI to an image file to load and use. - * If it is a URI, a new Image object will be constructed and assigned to the .image property. - **/ - function Bitmap(imageOrUri) { - this.DisplayObject_constructor(); - - - // public properties: - /** - * The image to render. This can be an Image, a Canvas, or a Video. Not all browsers (especially - * mobile browsers) support drawing video to a canvas. - * @property image - * @type HTMLImageElement | HTMLCanvasElement | HTMLVideoElement - **/ - if (typeof imageOrUri == "string") { - this.image = document.createElement("img"); - this.image.src = imageOrUri; - } else { - this.image = imageOrUri; - } - - /** - * Specifies an area of the source image to draw. If omitted, the whole image will be drawn. - * Note that video sources must have a width / height set to work correctly with `sourceRect`. - * @property sourceRect - * @type Rectangle - * @default null - */ - this.sourceRect = null; - } - var p = createjs.extend(Bitmap, createjs.DisplayObject); - - -// public methods: - /** - * Constructor alias for backwards compatibility. This method will be removed in future versions. - * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}. - * @method initialize - * @deprecated in favour of `createjs.promote()` - **/ - p.initialize = Bitmap; // TODO: deprecated. - - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var image = this.image; - var hasContent = this.cacheCanvas || (image && (image.naturalWidth || image.getContext || image.readyState >= 2)); - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - * @return {Boolean} - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache) || !this.image) { return true; } - var img = this.image, rect = this.sourceRect; - if (rect) { - // some browsers choke on out of bound values, so we'll fix them: - var x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height, x = 0, y = 0, w = img.width, h = img.height; - if (x1 < 0) { x -= x1; x1 = 0; } - if (x2 > w) { x2 = w; } - if (y1 < 0) { y -= y1; y1 = 0; } - if (y2 > h) { y2 = h; } - ctx.drawImage(img, x1, y1, x2-x1, y2-y1, x, y, x2-x1, y2-y1); - } else { - ctx.drawImage(img, 0, 0); - } - return true; - }; - - //Note, the doc sections below document using the specified APIs (from DisplayObject) from - //Bitmap. This is why they have no method implementations. - - /** - * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances. - * You should not cache Bitmap instances as it can degrade performance. - * - * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work. - * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}} - * method. - * @method cache - **/ - - /** - * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances. - * You should not cache Bitmap instances as it can degrade performance. - * - * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work. - * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}} - * method. - * @method updateCache - **/ - - /** - * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances. - * You should not cache Bitmap instances as it can degrade performance. - * - * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work. - * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}} - * method. - * @method uncache - **/ - - /** - * Docced in superclass. - */ - p.getBounds = function() { - var rect = this.DisplayObject_getBounds(); - if (rect) { return rect; } - var image = this.image, o = this.sourceRect || image; - var hasContent = (image && (image.naturalWidth || image.getContext || image.readyState >= 2)); - return hasContent ? this._rectangle.setValues(0, 0, o.width, o.height) : null; - }; - - /** - * Returns a clone of the Bitmap instance. - * @method clone - * @return {Bitmap} a clone of the Bitmap instance. - **/ - p.clone = function() { - var o = new Bitmap(this.image); - if (this.sourceRect) { o.sourceRect = this.sourceRect.clone(); } - this._cloneProps(o); - return o; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Bitmap (name="+ this.name +")]"; - }; - - - createjs.Bitmap = createjs.promote(Bitmap, "DisplayObject"); -}()); - -//############################################################################## -// Sprite.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Displays a frame or sequence of frames (ie. an animation) from a SpriteSheet instance. A sprite sheet is a series of - * images (usually animation frames) combined into a single image. For example, an animation consisting of 8 100x100 - * images could be combined into a 400x200 sprite sheet (4 frames across by 2 high). You can display individual frames, - * play frames as an animation, and even sequence animations together. - * - * See the {{#crossLink "SpriteSheet"}}{{/crossLink}} class for more information on setting up frames and animations. - * - *

    Example

    - * - * var instance = new createjs.Sprite(spriteSheet); - * instance.gotoAndStop("frameName"); - * - * Until {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} or {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}} is called, - * only the first defined frame defined in the sprite sheet will be displayed. - * - * @class Sprite - * @extends DisplayObject - * @constructor - * @param {SpriteSheet} spriteSheet The SpriteSheet instance to play back. This includes the source image(s), frame - * dimensions, and frame data. See {{#crossLink "SpriteSheet"}}{{/crossLink}} for more information. - * @param {String|Number} [frameOrAnimation] The frame number or animation to play initially. - **/ - function Sprite(spriteSheet, frameOrAnimation) { - this.DisplayObject_constructor(); - - - // public properties: - /** - * The frame index that will be drawn when draw is called. Note that with some {{#crossLink "SpriteSheet"}}{{/crossLink}} - * definitions, this will advance non-sequentially. This will always be an integer value. - * @property currentFrame - * @type {Number} - * @default 0 - * @readonly - **/ - this.currentFrame = 0; - - /** - * Returns the name of the currently playing animation. - * @property currentAnimation - * @type {String} - * @final - * @readonly - **/ - this.currentAnimation = null; - - /** - * Prevents the animation from advancing each tick automatically. For example, you could create a sprite - * sheet of icons, set paused to true, and display the appropriate icon by setting currentFrame. - * @property paused - * @type {Boolean} - * @default false - **/ - this.paused = true; - - /** - * The SpriteSheet instance to play back. This includes the source image, frame dimensions, and frame - * data. See {{#crossLink "SpriteSheet"}}{{/crossLink}} for more information. - * @property spriteSheet - * @type {SpriteSheet} - * @readonly - **/ - this.spriteSheet = spriteSheet; - - /** - * Specifies the current frame index within the currently playing animation. When playing normally, this will increase - * from 0 to n-1, where n is the number of frames in the current animation. - * - * This could be a non-integer value if - * using time-based playback (see {{#crossLink "Sprite/framerate"}}{{/crossLink}}, or if the animation's speed is - * not an integer. - * @property currentAnimationFrame - * @type {Number} - * @default 0 - **/ - this.currentAnimationFrame = 0; - - /** - * By default Sprite instances advance one frame per tick. Specifying a framerate for the Sprite (or its related - * SpriteSheet) will cause it to advance based on elapsed time between ticks as appropriate to maintain the target - * framerate. - * - * For example, if a Sprite with a framerate of 10 is placed on a Stage being updated at 40fps, then the Sprite will - * advance roughly one frame every 4 ticks. This will not be exact, because the time between each tick will - * vary slightly between frames. - * - * This feature is dependent on the tick event object (or an object with an appropriate "delta" property) being - * passed into {{#crossLink "Stage/update"}}{{/crossLink}}. - * @property framerate - * @type {Number} - * @default 0 - **/ - this.framerate = 0; - - - // private properties: - /** - * Current animation object. - * @property _animation - * @protected - * @type {Object} - * @default null - **/ - this._animation = null; - - /** - * Current frame index. - * @property _currentFrame - * @protected - * @type {Number} - * @default null - **/ - this._currentFrame = null; - - /** - * Skips the next auto advance. Used by gotoAndPlay to avoid immediately jumping to the next frame - * @property _skipAdvance - * @protected - * @type {Boolean} - * @default false - **/ - this._skipAdvance = false; - - - if (frameOrAnimation != null) { this.gotoAndPlay(frameOrAnimation); } - } - var p = createjs.extend(Sprite, createjs.DisplayObject); - - /** - * Constructor alias for backwards compatibility. This method will be removed in future versions. - * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}. - * @method initialize - * @deprecated in favour of `createjs.promote()` - **/ - p.initialize = Sprite; // TODO: Deprecated. This is for backwards support of FlashCC spritesheet export. - - -// events: - /** - * Dispatched when an animation reaches its ends. - * @event animationend - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {String} name The name of the animation that just ended. - * @param {String} next The name of the next animation that will be played, or null. This will be the same as name if the animation is looping. - * @since 0.6.0 - */ - - /** - * Dispatched any time the current frame changes. For example, this could be due to automatic advancement on a tick, - * or calling gotoAndPlay() or gotoAndStop(). - * @event change - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - */ - - -// public methods: - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var hasContent = this.cacheCanvas || this.spriteSheet.complete; - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; } - this._normalizeFrame(); - var o = this.spriteSheet.getFrame(this._currentFrame|0); - if (!o) { return false; } - var rect = o.rect; - if (rect.width && rect.height) { ctx.drawImage(o.image, rect.x, rect.y, rect.width, rect.height, -o.regX, -o.regY, rect.width, rect.height); } - return true; - }; - - //Note, the doc sections below document using the specified APIs (from DisplayObject) from - //Bitmap. This is why they have no method implementations. - - /** - * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances. - * You should not cache Sprite instances as it can degrade performance. - * @method cache - **/ - - /** - * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances. - * You should not cache Sprite instances as it can degrade performance. - * @method updateCache - **/ - - /** - * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances. - * You should not cache Sprite instances as it can degrade performance. - * @method uncache - **/ - - /** - * Play (unpause) the current animation. The Sprite will be paused if either {{#crossLink "Sprite/stop"}}{{/crossLink}} - * or {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} is called. Single frame animations will remain - * unchanged. - * @method play - **/ - p.play = function() { - this.paused = false; - }; - - /** - * Stop playing a running animation. The Sprite will be playing if {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}} - * is called. Note that calling {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}} or {{#crossLink "Sprite/play"}}{{/crossLink}} - * will resume playback. - * @method stop - **/ - p.stop = function() { - this.paused = true; - }; - - /** - * Sets paused to false and plays the specified animation name, named frame, or frame number. - * @method gotoAndPlay - * @param {String|Number} frameOrAnimation The frame number or animation name that the playhead should move to - * and begin playing. - **/ - p.gotoAndPlay = function(frameOrAnimation) { - this.paused = false; - this._skipAdvance = true; - this._goto(frameOrAnimation); - }; - - /** - * Sets paused to true and seeks to the specified animation name, named frame, or frame number. - * @method gotoAndStop - * @param {String|Number} frameOrAnimation The frame number or animation name that the playhead should move to - * and stop. - **/ - p.gotoAndStop = function(frameOrAnimation) { - this.paused = true; - this._goto(frameOrAnimation); - }; - - /** - * Advances the playhead. This occurs automatically each tick by default. - * @param [time] {Number} The amount of time in ms to advance by. Only applicable if framerate is set on the Sprite - * or its SpriteSheet. - * @method advance - */ - p.advance = function(time) { - var fps = this.framerate || this.spriteSheet.framerate; - var t = (fps && time != null) ? time/(1000/fps) : 1; - this._normalizeFrame(t); - }; - - /** - * Returns a {{#crossLink "Rectangle"}}{{/crossLink}} instance defining the bounds of the current frame relative to - * the origin. For example, a 90 x 70 frame with regX=50 and regY=40 would return a - * rectangle with [x=-50, y=-40, width=90, height=70]. This ignores transformations on the display object. - * - * Also see the SpriteSheet {{#crossLink "SpriteSheet/getFrameBounds"}}{{/crossLink}} method. - * @method getBounds - * @return {Rectangle} A Rectangle instance. Returns null if the frame does not exist, or the image is not fully - * loaded. - **/ - p.getBounds = function() { - // TODO: should this normalizeFrame? - return this.DisplayObject_getBounds() || this.spriteSheet.getFrameBounds(this.currentFrame, this._rectangle); - }; - - /** - * Returns a clone of the Sprite instance. Note that the same SpriteSheet is shared between cloned - * instances. - * @method clone - * @return {Sprite} a clone of the Sprite instance. - **/ - p.clone = function() { - return this._cloneProps(new Sprite(this.spriteSheet)); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Sprite (name="+ this.name +")]"; - }; - -// private methods: - /** - * @method _cloneProps - * @param {Sprite} o - * @return {Sprite} o - * @protected - **/ - p._cloneProps = function(o) { - this.DisplayObject__cloneProps(o); - o.currentFrame = this.currentFrame; - o.currentAnimation = this.currentAnimation; - o.paused = this.paused; - o.currentAnimationFrame = this.currentAnimationFrame; - o.framerate = this.framerate; - - o._animation = this._animation; - o._currentFrame = this._currentFrame; - o._skipAdvance = this._skipAdvance; - return o; - }; - - /** - * Advances the currentFrame if paused is not true. This is called automatically when the {{#crossLink "Stage"}}{{/crossLink}} - * ticks. - * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs. - * @protected - * @method _tick - **/ - p._tick = function(evtObj) { - if (!this.paused) { - if (!this._skipAdvance) { this.advance(evtObj&&evtObj.delta); } - this._skipAdvance = false; - } - this.DisplayObject__tick(evtObj); - }; - - - /** - * Normalizes the current frame, advancing animations and dispatching callbacks as appropriate. - * @protected - * @method _normalizeFrame - **/ - p._normalizeFrame = function(frameDelta) { - frameDelta = frameDelta || 0; - var animation = this._animation; - var paused = this.paused; - var frame = this._currentFrame; - var l; - - if (animation) { - var speed = animation.speed || 1; - var animFrame = this.currentAnimationFrame; - l = animation.frames.length; - if (animFrame + frameDelta * speed >= l) { - var next = animation.next; - if (this._dispatchAnimationEnd(animation, frame, paused, next, l - 1)) { - // something changed in the event stack, so we shouldn't make any more changes here. - return; - } else if (next) { - // sequence. Automatically calls _normalizeFrame again with the remaining frames. - return this._goto(next, frameDelta - (l - animFrame) / speed); - } else { - // end. - this.paused = true; - animFrame = animation.frames.length - 1; - } - } else { - animFrame += frameDelta * speed; - } - this.currentAnimationFrame = animFrame; - this._currentFrame = animation.frames[animFrame | 0] - } else { - frame = (this._currentFrame += frameDelta); - l = this.spriteSheet.getNumFrames(); - if (frame >= l && l > 0) { - if (!this._dispatchAnimationEnd(animation, frame, paused, l - 1)) { - // looped. - if ((this._currentFrame -= l) >= l) { return this._normalizeFrame(); } - } - } - } - frame = this._currentFrame | 0; - if (this.currentFrame != frame) { - this.currentFrame = frame; - this.dispatchEvent("change"); - } - }; - - /** - * Dispatches the "animationend" event. Returns true if a handler changed the animation (ex. calling {{#crossLink "Sprite/stop"}}{{/crossLink}}, - * {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}}, etc.) - * @property _dispatchAnimationEnd - * @private - * @type {Function} - **/ - p._dispatchAnimationEnd = function(animation, frame, paused, next, end) { - var name = animation ? animation.name : null; - if (this.hasEventListener("animationend")) { - var evt = new createjs.Event("animationend"); - evt.name = name; - evt.next = next; - this.dispatchEvent(evt); - } - // did the animation get changed in the event stack?: - var changed = (this._animation != animation || this._currentFrame != frame); - // if the animation hasn't changed, but the sprite was paused, then we want to stick to the last frame: - if (!changed && !paused && this.paused) { this.currentAnimationFrame = end; changed = true; } - return changed; - }; - - /** - * Moves the playhead to the specified frame number or animation. - * @method _goto - * @param {String|Number} frameOrAnimation The frame number or animation that the playhead should move to. - * @param {Boolean} [frame] The frame of the animation to go to. Defaults to 0. - * @protected - **/ - p._goto = function(frameOrAnimation, frame) { - this.currentAnimationFrame = 0; - if (isNaN(frameOrAnimation)) { - var data = this.spriteSheet.getAnimation(frameOrAnimation); - if (data) { - this._animation = data; - this.currentAnimation = frameOrAnimation; - this._normalizeFrame(frame); - } - } else { - this.currentAnimation = this._animation = null; - this._currentFrame = frameOrAnimation; - this._normalizeFrame(); - } - }; - - - createjs.Sprite = createjs.promote(Sprite, "DisplayObject"); -}()); - -//############################################################################## -// Shape.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * A Shape allows you to display vector art in the display list. It composites a {{#crossLink "Graphics"}}{{/crossLink}} - * instance which exposes all of the vector drawing methods. The Graphics instance can be shared between multiple Shape - * instances to display the same vector graphics with different positions or transforms. - * - * If the vector art will not - * change between draws, you may want to use the {{#crossLink "DisplayObject/cache"}}{{/crossLink}} method to reduce the - * rendering cost. - * - *

    Example

    - * - * var graphics = new createjs.Graphics().beginFill("#ff0000").drawRect(0, 0, 100, 100); - * var shape = new createjs.Shape(graphics); - * - * //Alternatively use can also use the graphics property of the Shape class to renderer the same as above. - * var shape = new createjs.Shape(); - * shape.graphics.beginFill("#ff0000").drawRect(0, 0, 100, 100); - * - * @class Shape - * @extends DisplayObject - * @constructor - * @param {Graphics} graphics Optional. The graphics instance to display. If null, a new Graphics instance will be created. - **/ - function Shape(graphics) { - this.DisplayObject_constructor(); - - - // public properties: - /** - * The graphics instance to display. - * @property graphics - * @type Graphics - **/ - this.graphics = graphics ? graphics : new createjs.Graphics(); - } - var p = createjs.extend(Shape, createjs.DisplayObject); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** - * Returns true or false indicating whether the Shape would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the Shape would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var hasContent = this.cacheCanvas || (this.graphics && !this.graphics.isEmpty()); - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent); - }; - - /** - * Draws the Shape into the specified context ignoring its visible, alpha, shadow, and transform. Returns true if - * the draw was handled (useful for overriding functionality). - * - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. For example, - * used for drawing the cache (to prevent it from simply drawing an existing cache back into itself). - * @return {Boolean} - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; } - this.graphics.draw(ctx, this); - return true; - }; - - /** - * Returns a clone of this Shape. Some properties that are specific to this instance's current context are reverted to - * their defaults (for example .parent). - * @method clone - * @param {Boolean} recursive If true, this Shape's {{#crossLink "Graphics"}}{{/crossLink}} instance will also be - * cloned. If false, the Graphics instance will be shared with the new Shape. - **/ - p.clone = function(recursive) { - var g = (recursive && this.graphics) ? this.graphics.clone() : this.graphics; - return this._cloneProps(new Shape(g)); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Shape (name="+ this.name +")]"; - }; - - - createjs.Shape = createjs.promote(Shape, "DisplayObject"); -}()); - -//############################################################################## -// Text.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Display one or more lines of dynamic text (not user editable) in the display list. Line wrapping support (using the - * lineWidth) is very basic, wrapping on spaces and tabs only. Note that as an alternative to Text, you can position HTML - * text above or below the canvas relative to items in the display list using the {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} - * method, or using {{#crossLink "DOMElement"}}{{/crossLink}}. - * - * Please note that Text does not support HTML text, and can only display one font style at a time. To use - * multiple font styles, you will need to create multiple text instances, and position them manually. - * - *

    Example

    - * - * var text = new createjs.Text("Hello World", "20px Arial", "#ff7700"); - * text.x = 100; - * text.textBaseline = "alphabetic"; - * - * CreateJS Text supports web fonts (the same rules as Canvas). The font must be loaded and supported by the browser - * before it can be displayed. - * - * Note: Text can be expensive to generate, so cache instances where possible. Be aware that not all - * browsers will render Text exactly the same. - * @class Text - * @extends DisplayObject - * @constructor - * @param {String} [text] The text to display. - * @param {String} [font] The font style to use. Any valid value for the CSS font attribute is acceptable (ex. "bold - * 36px Arial"). - * @param {String} [color] The color to draw the text in. Any valid value for the CSS color attribute is acceptable (ex. - * "#F00", "red", or "#FF0000"). - **/ - function Text(text, font, color) { - this.DisplayObject_constructor(); - - - // public properties: - /** - * The text to display. - * @property text - * @type String - **/ - this.text = text; - - /** - * The font style to use. Any valid value for the CSS font attribute is acceptable (ex. "bold 36px Arial"). - * @property font - * @type String - **/ - this.font = font; - - /** - * The color to draw the text in. Any valid value for the CSS color attribute is acceptable (ex. "#F00"). Default is "#000". - * It will also accept valid canvas fillStyle values. - * @property color - * @type String - **/ - this.color = color; - - /** - * The horizontal text alignment. Any of "start", "end", "left", "right", and "center". For detailed - * information view the - * - * whatwg spec. Default is "left". - * @property textAlign - * @type String - **/ - this.textAlign = "left"; - - /** - * The vertical alignment point on the font. Any of "top", "hanging", "middle", "alphabetic", "ideographic", or - * "bottom". For detailed information view the - * whatwg spec. Default is "top". - * @property textBaseline - * @type String - */ - this.textBaseline = "top"; - - /** - * The maximum width to draw the text. If maxWidth is specified (not null), the text will be condensed or - * shrunk to make it fit in this width. For detailed information view the - * - * whatwg spec. - * @property maxWidth - * @type Number - */ - this.maxWidth = null; - - /** - * If greater than 0, the text will be drawn as a stroke (outline) of the specified width. - * @property outline - * @type Number - **/ - this.outline = 0; - - /** - * Indicates the line height (vertical distance between baselines) for multi-line text. If null or 0, - * the value of getMeasuredLineHeight is used. - * @property lineHeight - * @type Number - **/ - this.lineHeight = 0; - - /** - * Indicates the maximum width for a line of text before it is wrapped to multiple lines. If null, - * the text will not be wrapped. - * @property lineWidth - * @type Number - **/ - this.lineWidth = null; - } - var p = createjs.extend(Text, createjs.DisplayObject); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// static properties: - /** - * @property _workingContext - * @type CanvasRenderingContext2D - * @private - **/ - var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas")); - if (canvas.getContext) { Text._workingContext = canvas.getContext("2d"); canvas.width = canvas.height = 1; } - - -// constants: - /** - * Lookup table for the ratio to offset bounds x calculations based on the textAlign property. - * @property H_OFFSETS - * @type Object - * @protected - * @static - **/ - Text.H_OFFSETS = {start: 0, left: 0, center: -0.5, end: -1, right: -1}; - - /** - * Lookup table for the ratio to offset bounds y calculations based on the textBaseline property. - * @property H_OFFSETS - * @type Object - * @protected - * @static - **/ - Text.V_OFFSETS = {top: 0, hanging: -0.01, middle: -0.4, alphabetic: -0.8, ideographic: -0.85, bottom: -1}; - - -// public methods: - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var hasContent = this.cacheCanvas || (this.text != null && this.text !== ""); - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent); - }; - - /** - * Draws the Text into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; } - - var col = this.color || "#000"; - if (this.outline) { ctx.strokeStyle = col; ctx.lineWidth = this.outline*1; } - else { ctx.fillStyle = col; } - - this._drawText(this._prepContext(ctx)); - return true; - }; - - /** - * Returns the measured, untransformed width of the text without wrapping. Use getBounds for a more robust value. - * @method getMeasuredWidth - * @return {Number} The measured, untransformed width of the text. - **/ - p.getMeasuredWidth = function() { - return this._getMeasuredWidth(this.text); - }; - - /** - * Returns an approximate line height of the text, ignoring the lineHeight property. This is based on the measured - * width of a "M" character multiplied by 1.2, which provides an approximate line height for most fonts. - * @method getMeasuredLineHeight - * @return {Number} an approximate line height of the text, ignoring the lineHeight property. This is - * based on the measured width of a "M" character multiplied by 1.2, which approximates em for most fonts. - **/ - p.getMeasuredLineHeight = function() { - return this._getMeasuredWidth("M")*1.2; - }; - - /** - * Returns the approximate height of multi-line text by multiplying the number of lines against either the - * lineHeight (if specified) or {{#crossLink "Text/getMeasuredLineHeight"}}{{/crossLink}}. Note that - * this operation requires the text flowing logic to run, which has an associated CPU cost. - * @method getMeasuredHeight - * @return {Number} The approximate height of the untransformed multi-line text. - **/ - p.getMeasuredHeight = function() { - return this._drawText(null,{}).height; - }; - - /** - * Docced in superclass. - */ - p.getBounds = function() { - var rect = this.DisplayObject_getBounds(); - if (rect) { return rect; } - if (this.text == null || this.text === "") { return null; } - var o = this._drawText(null, {}); - var w = (this.maxWidth && this.maxWidth < o.width) ? this.maxWidth : o.width; - var x = w * Text.H_OFFSETS[this.textAlign||"left"]; - var lineHeight = this.lineHeight||this.getMeasuredLineHeight(); - var y = lineHeight * Text.V_OFFSETS[this.textBaseline||"top"]; - return this._rectangle.setValues(x, y, w, o.height); - }; - - /** - * Returns an object with width, height, and lines properties. The width and height are the visual width and height - * of the drawn text. The lines property contains an array of strings, one for - * each line of text that will be drawn, accounting for line breaks and wrapping. These strings have trailing - * whitespace removed. - * @method getMetrics - * @return {Object} An object with width, height, and lines properties. - **/ - p.getMetrics = function() { - var o = {lines:[]}; - o.lineHeight = this.lineHeight || this.getMeasuredLineHeight(); - o.vOffset = o.lineHeight * Text.V_OFFSETS[this.textBaseline||"top"]; - return this._drawText(null, o, o.lines); - }; - - /** - * Returns a clone of the Text instance. - * @method clone - * @return {Text} a clone of the Text instance. - **/ - p.clone = function() { - return this._cloneProps(new Text(this.text, this.font, this.color)); - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Text (text="+ (this.text.length > 20 ? this.text.substr(0, 17)+"..." : this.text) +")]"; - }; - - -// private methods: - /** - * @method _cloneProps - * @param {Text} o - * @protected - * @return {Text} o - **/ - p._cloneProps = function(o) { - this.DisplayObject__cloneProps(o); - o.textAlign = this.textAlign; - o.textBaseline = this.textBaseline; - o.maxWidth = this.maxWidth; - o.outline = this.outline; - o.lineHeight = this.lineHeight; - o.lineWidth = this.lineWidth; - return o; - }; - - /** - * @method _getWorkingContext - * @param {CanvasRenderingContext2D} ctx - * @return {CanvasRenderingContext2D} - * @protected - **/ - p._prepContext = function(ctx) { - ctx.font = this.font||"10px sans-serif"; - ctx.textAlign = this.textAlign||"left"; - ctx.textBaseline = this.textBaseline||"top"; - return ctx; - }; - - /** - * Draws multiline text. - * @method _drawText - * @param {CanvasRenderingContext2D} ctx - * @param {Object} o - * @param {Array} lines - * @return {Object} - * @protected - **/ - p._drawText = function(ctx, o, lines) { - var paint = !!ctx; - if (!paint) { - ctx = Text._workingContext; - ctx.save(); - this._prepContext(ctx); - } - var lineHeight = this.lineHeight||this.getMeasuredLineHeight(); - - var maxW = 0, count = 0; - var hardLines = String(this.text).split(/(?:\r\n|\r|\n)/); - for (var i=0, l=hardLines.length; i this.lineWidth) { - // text wrapping: - var words = str.split(/(\s)/); - str = words[0]; - w = ctx.measureText(str).width; - - for (var j=1, jl=words.length; j this.lineWidth) { - if (paint) { this._drawTextLine(ctx, str, count*lineHeight); } - if (lines) { lines.push(str); } - if (w > maxW) { maxW = w; } - str = words[j+1]; - w = ctx.measureText(str).width; - count++; - } else { - str += words[j] + words[j+1]; - w += wordW; - } - } - } - - if (paint) { this._drawTextLine(ctx, str, count*lineHeight); } - if (lines) { lines.push(str); } - if (o && w == null) { w = ctx.measureText(str).width; } - if (w > maxW) { maxW = w; } - count++; - } - - if (o) { - o.width = maxW; - o.height = count*lineHeight; - } - if (!paint) { ctx.restore(); } - return o; - }; - - /** - * @method _drawTextLine - * @param {CanvasRenderingContext2D} ctx - * @param {String} text - * @param {Number} y - * @protected - **/ - p._drawTextLine = function(ctx, text, y) { - // Chrome 17 will fail to draw the text if the last param is included but null, so we feed it a large value instead: - if (this.outline) { ctx.strokeText(text, 0, y, this.maxWidth||0xFFFF); } - else { ctx.fillText(text, 0, y, this.maxWidth||0xFFFF); } - }; - - - /** - * @method _getMeasuredWidth - * @param {String} text - * @protected - **/ - p._getMeasuredWidth = function(text) { - var ctx = Text._workingContext; - ctx.save(); - var w = this._prepContext(ctx).measureText(text).width; - ctx.restore(); - return w; - }; - - - createjs.Text = createjs.promote(Text, "DisplayObject"); -}()); - -//############################################################################## -// BitmapText.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - -// constructor: - /** - * Displays text using bitmap glyphs defined in a sprite sheet. Multi-line text is supported - * using new line characters, but automatic wrapping is not supported. See the - * {{#crossLink "BitmapText/spriteSheet:property"}}{{/crossLink}} - * property for more information on defining glyphs. - * - * Important: BitmapText extends Container, but is not designed to be used as one. - * As such, methods like addChild and removeChild are disabled. - * @class BitmapText - * @extends DisplayObject - * @param {String} [text=""] The text to display. - * @param {SpriteSheet} [spriteSheet=null] The spritesheet that defines the character glyphs. - * @constructor - **/ - function BitmapText(text, spriteSheet) { - this.Container_constructor(); - - - // public properties: - /** - * The text to display. - * @property text - * @type String - * @default "" - **/ - this.text = text||""; - - /** - * A SpriteSheet instance that defines the glyphs for this bitmap text. Each glyph/character - * should have a single frame animation defined in the sprite sheet named the same as - * corresponding character. For example, the following animation definition: - * - * "A": {frames: [0]} - * - * would indicate that the frame at index 0 of the spritesheet should be drawn for the "A" character. The short form - * is also acceptable: - * - * "A": 0 - * - * Note that if a character in the text is not found in the sprite sheet, it will also - * try to use the alternate case (upper or lower). - * - * See SpriteSheet for more information on defining sprite sheet data. - * @property spriteSheet - * @type SpriteSheet - * @default null - **/ - this.spriteSheet = spriteSheet; - - /** - * The height of each line of text. If 0, then it will use a line height calculated - * by checking for the height of the "1", "T", or "L" character (in that order). If - * those characters are not defined, it will use the height of the first frame of the - * sprite sheet. - * @property lineHeight - * @type Number - * @default 0 - **/ - this.lineHeight = 0; - - /** - * This spacing (in pixels) will be added after each character in the output. - * @property letterSpacing - * @type Number - * @default 0 - **/ - this.letterSpacing = 0; - - /** - * If a space character is not defined in the sprite sheet, then empty pixels equal to - * spaceWidth will be inserted instead. If 0, then it will use a value calculated - * by checking for the width of the "1", "l", "E", or "A" character (in that order). If - * those characters are not defined, it will use the width of the first frame of the - * sprite sheet. - * @property spaceWidth - * @type Number - * @default 0 - **/ - this.spaceWidth = 0; - - - // private properties: - /** - * @property _oldProps - * @type Object - * @protected - **/ - this._oldProps = {text:0,spriteSheet:0,lineHeight:0,letterSpacing:0,spaceWidth:0}; - } - var p = createjs.extend(BitmapText, createjs.Container); - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - -// static properties: - /** - * BitmapText uses Sprite instances to draw text. To reduce the creation and destruction of instances (and thus garbage collection), it maintains - * an internal object pool of sprite instances to reuse. Increasing this value can cause more sprites to be - * retained, slightly increasing memory use, but reducing instantiation. - * @property maxPoolSize - * @type Number - * @static - * @default 100 - **/ - BitmapText.maxPoolSize = 100; - - /** - * Sprite object pool. - * @type {Array} - * @static - * @private - */ - BitmapText._spritePool = []; - - -// public methods: - /** - * Docced in superclass. - **/ - p.draw = function(ctx, ignoreCache) { - if (this.DisplayObject_draw(ctx, ignoreCache)) { return; } - this._updateText(); - this.Container_draw(ctx, ignoreCache); - }; - - /** - * Docced in superclass. - **/ - p.getBounds = function() { - this._updateText(); - return this.Container_getBounds(); - }; - - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - var hasContent = this.cacheCanvas || (this.spriteSheet && this.spriteSheet.complete && this.text); - return !!(this.visible && this.alpha > 0 && this.scaleX !== 0 && this.scaleY !== 0 && hasContent); - }; - - p.clone = function() { - return this._cloneProps(new BitmapText(this.text, this.spriteSheet)); - }; - - /** - * Disabled in BitmapText. - * @method addChild - **/ - /** - * Disabled in BitmapText. - * @method addChildAt - **/ - /** - * Disabled in BitmapText. - * @method removeChild - **/ - /** - * Disabled in BitmapText. - * @method removeChildAt - **/ - /** - * Disabled in BitmapText. - * @method removeAllChildren - **/ - p.addChild = p.addChildAt = p.removeChild = p.removeChildAt = p.removeAllChildren = function() {}; - - -// private methods: - /** - * @method _cloneProps - * @param {BitmapText} o - * @return {BitmapText} o - * @protected - **/ - p._cloneProps = function(o) { - this.Container__cloneProps(o); - o.lineHeight = this.lineHeight; - o.letterSpacing = this.letterSpacing; - o.spaceWidth = this.spaceWidth; - return o; - }; - - /** - * @method _getFrameIndex - * @param {String} character - * @param {SpriteSheet} spriteSheet - * @return {Number} - * @protected - **/ - p._getFrameIndex = function(character, spriteSheet) { - var c, o = spriteSheet.getAnimation(character); - if (!o) { - (character != (c = character.toUpperCase())) || (character != (c = character.toLowerCase())) || (c=null); - if (c) { o = spriteSheet.getAnimation(c); } - } - return o && o.frames[0]; - }; - - /** - * @method _getFrame - * @param {String} character - * @param {SpriteSheet} spriteSheet - * @return {Object} - * @protected - **/ - p._getFrame = function(character, spriteSheet) { - var index = this._getFrameIndex(character, spriteSheet); - return index == null ? index : spriteSheet.getFrame(index); - }; - - /** - * @method _getLineHeight - * @param {SpriteSheet} ss - * @return {Number} - * @protected - **/ - p._getLineHeight = function(ss) { - var frame = this._getFrame("1",ss) || this._getFrame("T",ss) || this._getFrame("L",ss) || ss.getFrame(0); - return frame ? frame.rect.height : 1; - }; - /** - * @method _getSpaceWidth - * @param {SpriteSheet} ss - * @return {Number} - * @protected - **/ - p._getSpaceWidth = function(ss) { - var frame = this._getFrame("1",ss) || this._getFrame("l",ss) || this._getFrame("e",ss) || this._getFrame("a",ss) || ss.getFrame(0); - return frame ? frame.rect.width : 1; - }; - - /** - * @method _drawText - * @protected - **/ - p._updateText = function() { - var x=0, y=0, o=this._oldProps, change=false, spaceW=this.spaceWidth, lineH=this.lineHeight, ss=this.spriteSheet; - var pool=BitmapText._spritePool, kids=this.children, childIndex=0, numKids=kids.length, sprite; - - for (var n in o) { - if (o[n] != this[n]) { - o[n] = this[n]; - change = true; - } - } - if (!change) { return; } - - var hasSpace = !!this._getFrame(" ", ss); - if (!hasSpace && !spaceW) { spaceW = this._getSpaceWidth(ss); } - if (!lineH) { lineH = this._getLineHeight(ss); } - - for(var i=0, l=this.text.length; i childIndex) { - // faster than removeChild. - pool.push(sprite = kids.pop()); - sprite.parent = null; - numKids--; - } - if (pool.length > BitmapText.maxPoolSize) { pool.length = BitmapText.maxPoolSize; } - }; - - - createjs.BitmapText = createjs.promote(BitmapText, "Container"); -}()); - -//############################################################################## -// MovieClip.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * The MovieClip class associates a TweenJS Timeline with an EaselJS {{#crossLink "Container"}}{{/crossLink}}. It allows - * you to create objects which encapsulate timeline animations, state changes, and synched actions. Due to the - * complexities inherent in correctly setting up a MovieClip, it is largely intended for tool output and is not included - * in the main EaselJS library. - * - * Currently MovieClip only works properly if it is tick based (as opposed to time based) though some concessions have - * been made to support time-based timelines in the future. - * - *

    Example

    - * This example animates two shapes back and forth. The grey shape starts on the left, but we jump to a mid-point in - * the animation using {{#crossLink "MovieClip/gotoAndPlay"}}{{/crossLink}}. - * - * var stage = new createjs.Stage("canvas"); - * createjs.Ticker.addEventListener("tick", stage); - * - * var mc = new createjs.MovieClip(null, 0, true, {start:20}); - * stage.addChild(mc); - * - * var child1 = new createjs.Shape( - * new createjs.Graphics().beginFill("#999999") - * .drawCircle(30,30,30)); - * var child2 = new createjs.Shape( - * new createjs.Graphics().beginFill("#5a9cfb") - * .drawCircle(30,30,30)); - * - * mc.timeline.addTween( - * createjs.Tween.get(child1) - * .to({x:0}).to({x:60}, 50).to({x:0}, 50)); - * mc.timeline.addTween( - * createjs.Tween.get(child2) - * .to({x:60}).to({x:0}, 50).to({x:60}, 50)); - * - * mc.gotoAndPlay("start"); - * - * It is recommended to use tween.to() to animate and set properties (use no duration to have it set - * immediately), and the tween.wait() method to create delays between animations. Note that using the - * tween.set() method to affect properties will likely not provide the desired result. - * - * @class MovieClip - * @main MovieClip - * @extends Container - * @constructor - * @param {String} [mode=independent] Initial value for the mode property. One of {{#crossLink "MovieClip/INDEPENDENT:property"}}{{/crossLink}}, - * {{#crossLink "MovieClip/SINGLE_FRAME:property"}}{{/crossLink}}, or {{#crossLink "MovieClip/SYNCHED:property"}}{{/crossLink}}. - * The default is {{#crossLink "MovieClip/INDEPENDENT:property"}}{{/crossLink}}. - * @param {Number} [startPosition=0] Initial value for the {{#crossLink "MovieClip/startPosition:property"}}{{/crossLink}} - * property. - * @param {Boolean} [loop=true] Initial value for the {{#crossLink "MovieClip/loop:property"}}{{/crossLink}} - * property. The default is `true`. - * @param {Object} [labels=null] A hash of labels to pass to the {{#crossLink "MovieClip/timeline:property"}}{{/crossLink}} - * instance associated with this MovieClip. Labels only need to be passed if they need to be used. - **/ - function MovieClip(mode, startPosition, loop, labels) { - this.Container_constructor(); - !MovieClip.inited&&MovieClip.init(); // static init - - - // public properties: - /** - * Controls how this MovieClip advances its time. Must be one of 0 (INDEPENDENT), 1 (SINGLE_FRAME), or 2 (SYNCHED). - * See each constant for a description of the behaviour. - * @property mode - * @type String - * @default null - **/ - this.mode = mode||MovieClip.INDEPENDENT; - - /** - * Specifies what the first frame to play in this movieclip, or the only frame to display if mode is SINGLE_FRAME. - * @property startPosition - * @type Number - * @default 0 - */ - this.startPosition = startPosition || 0; - - /** - * Indicates whether this MovieClip should loop when it reaches the end of its timeline. - * @property loop - * @type Boolean - * @default true - */ - this.loop = loop; - - /** - * The current frame of the movieclip. - * @property currentFrame - * @type Number - * @default 0 - * @readonly - */ - this.currentFrame = 0; - - /** - * The TweenJS Timeline that is associated with this MovieClip. This is created automatically when the MovieClip - * instance is initialized. Animations are created by adding TweenJS Tween - * instances to the timeline. - * - *

    Example

    - * - * var tween = createjs.Tween.get(target).to({x:0}).to({x:100}, 30); - * var mc = new createjs.MovieClip(); - * mc.timeline.addTween(tween); - * - * Elements can be added and removed from the timeline by toggling an "_off" property - * using the tweenInstance.to() method. Note that using Tween.set is not recommended to - * create MovieClip animations. The following example will toggle the target off on frame 0, and then back on for - * frame 1. You can use the "visible" property to achieve the same effect. - * - * var tween = createjs.Tween.get(target).to({_off:false}) - * .wait(1).to({_off:true}) - * .wait(1).to({_off:false}); - * - * @property timeline - * @type Timeline - * @default null - */ - this.timeline = new createjs.Timeline(null, labels, {paused:true, position:startPosition, useTicks:true}); - - /** - * If true, the MovieClip's position will not advance when ticked. - * @property paused - * @type Boolean - * @default false - */ - this.paused = false; - - /** - * If true, actions in this MovieClip's tweens will be run when the playhead advances. - * @property actionsEnabled - * @type Boolean - * @default true - */ - this.actionsEnabled = true; - - /** - * If true, the MovieClip will automatically be reset to its first frame whenever the timeline adds - * it back onto the display list. This only applies to MovieClip instances with mode=INDEPENDENT. - *

    - * For example, if you had a character animation with a "body" child MovieClip instance - * with different costumes on each frame, you could set body.autoReset = false, so that - * you can manually change the frame it is on, without worrying that it will be reset - * automatically. - * @property autoReset - * @type Boolean - * @default true - */ - this.autoReset = true; - - /** - * An array of bounds for each frame in the MovieClip. This is mainly intended for tool output. - * @property frameBounds - * @type Array - * @default null - */ - this.frameBounds = this.frameBounds||null; // TODO: Deprecated. This is for backwards support of FlashCC - - /** - * By default MovieClip instances advance one frame per tick. Specifying a framerate for the MovieClip - * will cause it to advance based on elapsed time between ticks as appropriate to maintain the target - * framerate. - * - * For example, if a MovieClip with a framerate of 10 is placed on a Stage being updated at 40fps, then the MovieClip will - * advance roughly one frame every 4 ticks. This will not be exact, because the time between each tick will - * vary slightly between frames. - * - * This feature is dependent on the tick event object (or an object with an appropriate "delta" property) being - * passed into {{#crossLink "Stage/update"}}{{/crossLink}}. - * @property framerate - * @type {Number} - * @default null - **/ - this.framerate = null; - - - // private properties: - /** - * @property _synchOffset - * @type Number - * @default 0 - * @private - */ - this._synchOffset = 0; - - /** - * @property _prevPos - * @type Number - * @default -1 - * @private - */ - this._prevPos = -1; // TODO: evaluate using a ._reset Boolean prop instead of -1. - - /** - * @property _prevPosition - * @type Number - * @default 0 - * @private - */ - this._prevPosition = 0; - - /** - * The time remaining from the previous tick, only applicable when .framerate is set. - * @property _t - * @type Number - * @private - */ - this._t = 0; - - /** - * List of display objects that are actively being managed by the MovieClip. - * @property _managed - * @type Object - * @private - */ - this._managed = {}; - } - var p = createjs.extend(MovieClip, createjs.Container); - - -// constants: - /** - * The MovieClip will advance independently of its parent, even if its parent is paused. - * This is the default mode. - * @property INDEPENDENT - * @static - * @type String - * @default "independent" - * @readonly - **/ - MovieClip.INDEPENDENT = "independent"; - - /** - * The MovieClip will only display a single frame (as determined by the startPosition property). - * @property SINGLE_FRAME - * @static - * @type String - * @default "single" - * @readonly - **/ - MovieClip.SINGLE_FRAME = "single"; - - /** - * The MovieClip will be advanced only when its parent advances and will be synched to the position of - * the parent MovieClip. - * @property SYNCHED - * @static - * @type String - * @default "synched" - * @readonly - **/ - MovieClip.SYNCHED = "synched"; - - -// static properties: - MovieClip.inited = false; - - -// static methods: - MovieClip.init = function() { - if (MovieClip.inited) { return; } - // plugins introduce some overhead to Tween, so we only install this if an MC is instantiated. - MovieClipPlugin.install(); - MovieClip.inited = true; - }; - - -// getter / setters: - /** - * Use the {{#crossLink "MovieClip/labels:property"}}{{/crossLink}} property instead. - * @method getLabels - * @return {Array} - * @deprecated - **/ - p.getLabels = function() { - return this.timeline.getLabels(); - }; - - /** - * Use the {{#crossLink "MovieClip/currentLabel:property"}}{{/crossLink}} property instead. - * @method getCurrentLabel - * @return {String} - * @deprecated - **/ - p.getCurrentLabel = function() { - this._updateTimeline(); - return this.timeline.getCurrentLabel(); - }; - - /** - * Use the {{#crossLink "MovieClip/duration:property"}}{{/crossLink}} property instead. - * @method getDuration - * @return {Number} - * @protected - **/ - p.getDuration = function() { - return this.timeline.duration; - }; - - /** - * Returns an array of objects with label and position (aka frame) properties, sorted by position. - * Shortcut to TweenJS: Timeline.getLabels(); - * @property labels - * @type {Array} - * @readonly - **/ - - /** - * Returns the name of the label on or immediately before the current frame. See TweenJS: Timeline.getCurrentLabel() - * for more information. - * @property currentLabel - * @type {String} - * @readonly - **/ - - /** - * Returns the duration of this MovieClip in seconds or ticks. Identical to {{#crossLink "MovieClip/duration:property"}}{{/crossLink}} - * and provided for Flash API compatibility. - * @property totalFrames - * @type {Number} - * @readonly - **/ - - /** - * Returns the duration of this MovieClip in seconds or ticks. - * @property duration - * @type {Number} - * @readonly - **/ - try { - Object.defineProperties(p, { - labels: { get: p.getLabels }, - currentLabel: { get: p.getCurrentLabel }, - totalFrames: { get: p.getDuration }, - duration: { get: p.getDuration } - }); - } catch (e) {} - - -// public methods: - /** - * Constructor alias for backwards compatibility. This method will be removed in future versions. - * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}. - * @method initialize - * @deprecated in favour of `createjs.promote()` - **/ - p.initialize = MovieClip; // TODO: Deprecated. This is for backwards support of FlashCC - - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - **/ - p.isVisible = function() { - // children are placed in draw, so we can't determine if we have content. - return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0); - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - **/ - p.draw = function(ctx, ignoreCache) { - // draw to cache first: - if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; } - this._updateTimeline(); - this.Container_draw(ctx, ignoreCache); - return true; - }; - - /** - * Sets paused to false. - * @method play - **/ - p.play = function() { - this.paused = false; - }; - - /** - * Sets paused to true. - * @method stop - **/ - p.stop = function() { - this.paused = true; - }; - - /** - * Advances this movie clip to the specified position or label and sets paused to false. - * @method gotoAndPlay - * @param {String|Number} positionOrLabel The animation name or frame number to go to. - **/ - p.gotoAndPlay = function(positionOrLabel) { - this.paused = false; - this._goto(positionOrLabel); - }; - - /** - * Advances this movie clip to the specified position or label and sets paused to true. - * @method gotoAndStop - * @param {String|Number} positionOrLabel The animation or frame name to go to. - **/ - p.gotoAndStop = function(positionOrLabel) { - this.paused = true; - this._goto(positionOrLabel); - }; - - /** - * Advances the playhead. This occurs automatically each tick by default. - * @param [time] {Number} The amount of time in ms to advance by. Only applicable if framerate is set. - * @method advance - */ - p.advance = function(time) { - // TODO: should we worry at all about clips who change their own modes via frame scripts? - var independent = MovieClip.INDEPENDENT; - if (this.mode != independent) { return; } - - var o=this, fps = o.framerate; - while ((o = o.parent) && fps == null) { - if (o.mode == independent) { fps = o._framerate; } - } - this._framerate = fps; - - var t = (fps != null && fps != -1 && time != null) ? time/(1000/fps) + this._t : 1; - var frames = t|0; - this._t = t-frames; // leftover time - - while (!this.paused && frames--) { - this._prevPosition = (this._prevPos < 0) ? 0 : this._prevPosition+1; - this._updateTimeline(); - } - }; - - /** - * MovieClip instances cannot be cloned. - * @method clone - **/ - p.clone = function() { - // TODO: add support for this? Need to clone the Timeline & retarget tweens - pretty complex. - throw("MovieClip cannot be cloned.") - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[MovieClip (name="+ this.name +")]"; - }; - - -// private methods: - /** - * @method _tick - * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs. - * function. - * @protected - **/ - p._tick = function(evtObj) { - this.advance(evtObj&&evtObj.delta); - this.Container__tick(evtObj); - }; - - /** - * @method _goto - * @param {String|Number} positionOrLabel The animation name or frame number to go to. - * @protected - **/ - p._goto = function(positionOrLabel) { - var pos = this.timeline.resolve(positionOrLabel); - if (pos == null) { return; } - // prevent _updateTimeline from overwriting the new position because of a reset: - if (this._prevPos == -1) { this._prevPos = NaN; } - this._prevPosition = pos; - this._t = 0; - this._updateTimeline(); - }; - - /** - * @method _reset - * @private - **/ - p._reset = function() { - this._prevPos = -1; - this._t = this.currentFrame = 0; - this.paused = false; - }; - - /** - * @method _updateTimeline - * @protected - **/ - p._updateTimeline = function() { - var tl = this.timeline; - var synched = this.mode != MovieClip.INDEPENDENT; - tl.loop = (this.loop==null) ? true : this.loop; - - var pos = synched ? this.startPosition + (this.mode==MovieClip.SINGLE_FRAME?0:this._synchOffset) : (this._prevPos < 0 ? 0 : this._prevPosition); - var mode = synched || !this.actionsEnabled ? createjs.Tween.NONE : null; - - // pre-assign currentFrame so it is available to frame scripts: - this.currentFrame = tl._calcPosition(pos); - - // update timeline position, ignoring actions if this is a graphic. - tl.setPosition(pos, mode); - - this._prevPosition = tl._prevPosition; - if (this._prevPos == tl._prevPos) { return; } - this.currentFrame = this._prevPos = tl._prevPos; - - for (var n in this._managed) { this._managed[n] = 1; } - - var tweens = tl._tweens; - for (var i=0, l=tweens.length; i=0; i--) { - var id = kids[i].id; - if (this._managed[id] == 1) { - this.removeChildAt(i); - delete(this._managed[id]); - } - } - }; - - /** - * @method _setState - * @param {Array} state - * @param {Number} offset - * @protected - **/ - p._setState = function(state, offset) { - if (!state) { return; } - for (var i=state.length-1;i>=0;i--) { - var o = state[i]; - var target = o.t; - var props = o.p; - for (var n in props) { target[n] = props[n]; } - this._addManagedChild(target, offset); - } - }; - - /** - * Adds a child to the timeline, and sets it up as a managed child. - * @method _addManagedChild - * @param {MovieClip} child The child MovieClip to manage - * @param {Number} offset - * @private - **/ - p._addManagedChild = function(child, offset) { - if (child._off) { return; } - this.addChildAt(child,0); - - if (child instanceof MovieClip) { - child._synchOffset = offset; - // TODO: this does not precisely match Flash. Flash loses track of the clip if it is renamed or removed from the timeline, which causes it to reset. - if (child.mode == MovieClip.INDEPENDENT && child.autoReset && !this._managed[child.id]) { child._reset(); } - } - this._managed[child.id] = 2; - }; - - /** - * @method _getBounds - * @param {Matrix2D} matrix - * @param {Boolean} ignoreTransform - * @return {Rectangle} - * @protected - **/ - p._getBounds = function(matrix, ignoreTransform) { - var bounds = this.DisplayObject_getBounds(); - if (!bounds) { - this._updateTimeline(); - if (this.frameBounds) { bounds = this._rectangle.copy(this.frameBounds[this.currentFrame]); } - } - if (bounds) { return this._transformBounds(bounds, matrix, ignoreTransform); } - return this.Container__getBounds(matrix, ignoreTransform); - }; - - - createjs.MovieClip = createjs.promote(MovieClip, "Container"); - - - -// MovieClipPlugin for TweenJS: - /** - * This plugin works with TweenJS to prevent the startPosition - * property from tweening. - * @private - * @class MovieClipPlugin - * @constructor - **/ - function MovieClipPlugin() { - throw("MovieClipPlugin cannot be instantiated.") - } - - /** - * @method priority - * @private - **/ - MovieClipPlugin.priority = 100; // very high priority, should run first - - /** - * @method install - * @private - **/ - MovieClipPlugin.install = function() { - createjs.Tween.installPlugin(MovieClipPlugin, ["startPosition"]); - }; - - /** - * @method init - * @param {Tween} tween - * @param {String} prop - * @param {String|Number|Boolean} value - * @private - **/ - MovieClipPlugin.init = function(tween, prop, value) { - return value; - }; - - /** - * @method step - * @private - **/ - MovieClipPlugin.step = function() { - // unused. - }; - - /** - * @method tween - * @param {Tween} tween - * @param {String} prop - * @param {String | Number | Boolean} value - * @param {Array} startValues - * @param {Array} endValues - * @param {Number} ratio - * @param {Object} wait - * @param {Object} end - * @return {*} - */ - MovieClipPlugin.tween = function(tween, prop, value, startValues, endValues, ratio, wait, end) { - if (!(tween.target instanceof MovieClip)) { return value; } - return (ratio == 1 ? endValues[prop] : startValues[prop]); - }; - -}()); - -//############################################################################## -// SpriteSheetUtils.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * The SpriteSheetUtils class is a collection of static methods for working with {{#crossLink "SpriteSheet"}}{{/crossLink}}s. - * A sprite sheet is a series of images (usually animation frames) combined into a single image on a regular grid. For - * example, an animation consisting of 8 100x100 images could be combined into a 400x200 sprite sheet (4 frames across - * by 2 high). The SpriteSheetUtils class uses a static interface and should not be instantiated. - * @class SpriteSheetUtils - * @static - **/ - function SpriteSheetUtils() { - throw "SpriteSheetUtils cannot be instantiated"; - } - - -// private static properties: - /** - * @property _workingCanvas - * @static - * @type HTMLCanvasElement | Object - * @protected - */ - /** - * @property _workingContext - * @static - * @type CanvasRenderingContext2D - * @protected - */ - var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas")); - if (canvas.getContext) { - SpriteSheetUtils._workingCanvas = canvas; - SpriteSheetUtils._workingContext = canvas.getContext("2d"); - canvas.width = canvas.height = 1; - } - - -// public static methods: - /** - * This is an experimental method, and may be buggy. Please report issues.

    - * Extends the existing sprite sheet by flipping the original frames horizontally, vertically, or both, - * and adding appropriate animation & frame data. The flipped animations will have a suffix added to their names - * (_h, _v, _hv as appropriate). Make sure the sprite sheet images are fully loaded before using this method. - *

    - * For example:
    - * SpriteSheetUtils.addFlippedFrames(mySpriteSheet, true, true); - * The above would add frames that are flipped horizontally AND frames that are flipped vertically. - *

    - * Note that you can also flip any display object by setting its scaleX or scaleY to a negative value. On some - * browsers (especially those without hardware accelerated canvas) this can result in slightly degraded performance, - * which is why addFlippedFrames is available. - * @method addFlippedFrames - * @static - * @param {SpriteSheet} spriteSheet - * @param {Boolean} horizontal If true, horizontally flipped frames will be added. - * @param {Boolean} vertical If true, vertically flipped frames will be added. - * @param {Boolean} both If true, frames that are flipped both horizontally and vertically will be added. - * @deprecated Modern browsers perform better when flipping via a transform (ex. scaleX=-1) rendering this obsolete. - **/ - SpriteSheetUtils.addFlippedFrames = function(spriteSheet, horizontal, vertical, both) { - if (!horizontal && !vertical && !both) { return; } - - var count = 0; - if (horizontal) { SpriteSheetUtils._flip(spriteSheet,++count,true,false); } - if (vertical) { SpriteSheetUtils._flip(spriteSheet,++count,false,true); } - if (both) { SpriteSheetUtils._flip(spriteSheet,++count,true,true); } - }; - - /** - * Returns a single frame of the specified sprite sheet as a new PNG image. An example of when this may be useful is - * to use a spritesheet frame as the source for a bitmap fill. - * - * WARNING: In almost all cases it is better to display a single frame using a {{#crossLink "Sprite"}}{{/crossLink}} - * with a {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} call than it is to slice out a frame using this - * method and display it with a Bitmap instance. You can also crop an image using the {{#crossLink "Bitmap/sourceRect"}}{{/crossLink}} - * property of {{#crossLink "Bitmap"}}{{/crossLink}}. - * - * The extractFrame method may cause cross-domain warnings since it accesses pixels directly on the canvas. - * @method extractFrame - * @static - * @param {SpriteSheet} spriteSheet The SpriteSheet instance to extract a frame from. - * @param {Number|String} frameOrAnimation The frame number or animation name to extract. If an animation - * name is specified, only the first frame of the animation will be extracted. - * @return {HTMLImageElement} a single frame of the specified sprite sheet as a new PNG image. - */ - SpriteSheetUtils.extractFrame = function(spriteSheet, frameOrAnimation) { - if (isNaN(frameOrAnimation)) { - frameOrAnimation = spriteSheet.getAnimation(frameOrAnimation).frames[0]; - } - var data = spriteSheet.getFrame(frameOrAnimation); - if (!data) { return null; } - var r = data.rect; - var canvas = SpriteSheetUtils._workingCanvas; - canvas.width = r.width; - canvas.height = r.height; - SpriteSheetUtils._workingContext.drawImage(data.image, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height); - var img = document.createElement("img"); - img.src = canvas.toDataURL("image/png"); - return img; - }; - - /** - * Merges the rgb channels of one image with the alpha channel of another. This can be used to combine a compressed - * JPEG image containing color data with a PNG32 monochromatic image containing alpha data. With certain types of - * images (those with detail that lend itself to JPEG compression) this can provide significant file size savings - * versus a single RGBA PNG32. This method is very fast (generally on the order of 1-2 ms to run). - * @method mergeAlpha - * @static - * @param {HTMLImageElement} rbgImage The image (or canvas) containing the RGB channels to use. - * @param {HTMLImageElement} alphaImage The image (or canvas) containing the alpha channel to use. - * @param {HTMLCanvasElement} canvas Optional. If specified, this canvas will be used and returned. If not, a new canvas will be created. - * @return {HTMLCanvasElement} A canvas with the combined image data. This can be used as a source for Bitmap or SpriteSheet. - * @deprecated Tools such as ImageAlpha generally provide better results. This will be moved to sandbox in the future. - */ - SpriteSheetUtils.mergeAlpha = function(rgbImage, alphaImage, canvas) { - if (!canvas) { canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); } - canvas.width = Math.max(alphaImage.width, rgbImage.width); - canvas.height = Math.max(alphaImage.height, rgbImage.height); - var ctx = canvas.getContext("2d"); - ctx.save(); - ctx.drawImage(rgbImage,0,0); - ctx.globalCompositeOperation = "destination-in"; - ctx.drawImage(alphaImage,0,0); - ctx.restore(); - return canvas; - }; - - -// private static methods: - SpriteSheetUtils._flip = function(spriteSheet, count, h, v) { - var imgs = spriteSheet._images; - var canvas = SpriteSheetUtils._workingCanvas; - var ctx = SpriteSheetUtils._workingContext; - var il = imgs.length/count; - for (var i=0;iREMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// constants: - SpriteSheetBuilder.ERR_DIMENSIONS = "frame dimensions exceed max spritesheet dimensions"; - SpriteSheetBuilder.ERR_RUNNING = "a build is already running"; - -// events: - /** - * Dispatched when a build completes. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.6.0 - */ - - /** - * Dispatched when an asynchronous build has progress. - * @event progress - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Number} progress The current progress value (0-1). - * @since 0.6.0 - */ - - -// public methods: - /** - * Adds a frame to the {{#crossLink "SpriteSheet"}}{{/crossLink}}. Note that the frame will not be drawn until you - * call {{#crossLink "SpriteSheetBuilder/build"}}{{/crossLink}} method. The optional setup params allow you to have - * a function run immediately before the draw occurs. For example, this allows you to add a single source multiple - * times, but manipulate it or its children to change it to generate different frames. - * - * Note that the source's transformations (x, y, scale, rotate, alpha) will be ignored, except for regX/Y. To apply - * transforms to a source object and have them captured in the SpriteSheet, simply place it into a {{#crossLink "Container"}}{{/crossLink}} - * and pass in the Container as the source. - * @method addFrame - * @param {DisplayObject} source The source {{#crossLink "DisplayObject"}}{{/crossLink}} to draw as the frame. - * @param {Rectangle} [sourceRect] A {{#crossLink "Rectangle"}}{{/crossLink}} defining the portion of the - * source to draw to the frame. If not specified, it will look for a `getBounds` method, bounds property, or - * `nominalBounds` property on the source to use. If one is not found, the frame will be skipped. - * @param {Number} [scale=1] Optional. The scale to draw this frame at. Default is 1. - * @param {Function} [setupFunction] A function to call immediately before drawing this frame. It will be called with two parameters: the source, and setupData. - * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter. - * @return {Number} The index of the frame that was just added, or null if a sourceRect could not be determined. - **/ - p.addFrame = function(source, sourceRect, scale, setupFunction, setupData) { - if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; } - var rect = sourceRect||source.bounds||source.nominalBounds; - if (!rect&&source.getBounds) { rect = source.getBounds(); } - if (!rect) { return null; } - scale = scale||1; - return this._frames.push({source:source, sourceRect:rect, scale:scale, funct:setupFunction, data:setupData, index:this._frames.length, height:rect.height*scale})-1; - }; - - /** - * Adds an animation that will be included in the created {{#crossLink "SpriteSheet"}}{{/crossLink}}. - * @method addAnimation - * @param {String} name The name for the animation. - * @param {Array} frames An array of frame indexes that comprise the animation. Ex. [3,6,5] would describe an animation - * that played frame indexes 3, 6, and 5 in that order. - * @param {String} [next] Specifies the name of the animation to continue to after this animation ends. You can - * also pass false to have the animation stop when it ends. By default it will loop to the start of the same animation. - * @param {Number} [speed] Specifies a frame advance speed for this animation. For example, a value of 0.5 would - * cause the animation to advance every second tick. Note that earlier versions used `frequency` instead, which had - * the opposite effect. - **/ - p.addAnimation = function(name, frames, next, speed) { - if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; } - this._animations[name] = {frames:frames, next:next, speed:speed}; - }; - - /** - * This will take a {{#crossLink "MovieClip"}}{{/crossLink}} instance, and add its frames and labels to this - * builder. Labels will be added as an animation running from the label index to the next label. For example, if - * there is a label named "foo" at frame 0 and a label named "bar" at frame 10, in a MovieClip with 15 frames, it - * will add an animation named "foo" that runs from frame index 0 to 9, and an animation named "bar" that runs from - * frame index 10 to 14. - * - * Note that this will iterate through the full MovieClip with {{#crossLink "MovieClip/actionsEnabled:property"}}{{/crossLink}} - * set to `false`, ending on the last frame. - * @method addMovieClip - * @param {MovieClip} source The source MovieClip instance to add to the SpriteSheet. - * @param {Rectangle} [sourceRect] A {{#crossLink "Rectangle"}}{{/crossLink}} defining the portion of the source to - * draw to the frame. If not specified, it will look for a {{#crossLink "DisplayObject/getBounds"}}{{/crossLink}} - * method, `frameBounds` Array, `bounds` property, or `nominalBounds` property on the source to use. If one is not - * found, the MovieClip will be skipped. - * @param {Number} [scale=1] The scale to draw the movie clip at. - * @param {Function} [setupFunction] A function to call immediately before drawing each frame. It will be called - * with three parameters: the source, setupData, and the frame index. - * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter. - * @param {Function} [labelFunction] This method will be called for each MovieClip label that is added with four - * parameters: the label name, the source MovieClip instance, the starting frame index (in the movieclip timeline) - * and the end index. It must return a new name for the label/animation, or `false` to exclude the label. - **/ - p.addMovieClip = function(source, sourceRect, scale, setupFunction, setupData, labelFunction) { - if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; } - var rects = source.frameBounds; - var rect = sourceRect||source.bounds||source.nominalBounds; - if (!rect&&source.getBounds) { rect = source.getBounds(); } - if (!rect && !rects) { return; } - - var i, l, baseFrameIndex = this._frames.length; - var duration = source.timeline.duration; - for (i=0; i this.maxHeight) { throw SpriteSheetBuilder.ERR_DIMENSIONS; } - var y=0, x=0; - var img = 0; - while (frames.length) { - var o = this._fillRow(frames, y, img, dataFrames, pad); - if (o.w > x) { x = o.w; } - y += o.h; - if (!o.h || !frames.length) { - var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); - canvas.width = this._getSize(x,this.maxWidth); - canvas.height = this._getSize(y,this.maxHeight); - this._data.images[img] = canvas; - if (!o.h) { - x=y=0; - img++; - } - } - } - }; - - /** - * @method _setupMovieClipFrame - * @protected - * @return {Number} The width & height of the row. - **/ - p._setupMovieClipFrame = function(source, data) { - var ae = source.actionsEnabled; - source.actionsEnabled = false; - source.gotoAndStop(data.i); - source.actionsEnabled = ae; - data.f&&data.f(source, data.d, data.i); - }; - - /** - * @method _getSize - * @protected - * @return {Number} The width & height of the row. - **/ - p._getSize = function(size,max) { - var pow = 4; - while (Math.pow(2,++pow) < size){} - return Math.min(max,Math.pow(2,pow)); - }; - - /** - * @method _fillRow - * @param {Array} frames - * @param {Number} y - * @param {HTMLImageElement} img - * @param {Object} dataFrames - * @param {Number} pad - * @protected - * @return {Number} The width & height of the row. - **/ - p._fillRow = function(frames, y, img, dataFrames, pad) { - var w = this.maxWidth; - var maxH = this.maxHeight; - y += pad; - var h = maxH-y; - var x = pad; - var height = 0; - for (var i=frames.length-1; i>=0; i--) { - var frame = frames[i]; - var sc = this._scale*frame.scale; - var rect = frame.sourceRect; - var source = frame.source; - var rx = Math.floor(sc*rect.x-pad); - var ry = Math.floor(sc*rect.y-pad); - var rh = Math.ceil(sc*rect.height+pad*2); - var rw = Math.ceil(sc*rect.width+pad*2); - if (rw > w) { throw SpriteSheetBuilder.ERR_DIMENSIONS; } - if (rh > h || x+rw > w) { continue; } - frame.img = img; - frame.rect = new createjs.Rectangle(x,y,rw,rh); - height = height || rh; - frames.splice(i,1); - dataFrames[frame.index] = [x,y,rw,rh,img,Math.round(-rx+sc*source.regX-pad),Math.round(-ry+sc*source.regY-pad)]; - x += rw; - } - return {w:x, h:height}; - }; - - /** - * @method _endBuild - * @protected - **/ - p._endBuild = function() { - this.spriteSheet = new createjs.SpriteSheet(this._data); - this._data = null; - this.progress = 1; - this.dispatchEvent("complete"); - }; - - /** - * @method _run - * @protected - **/ - p._run = function() { - var ts = Math.max(0.01, Math.min(0.99, this.timeSlice||0.3))*50; - var t = (new Date()).getTime()+ts; - var complete = false; - while (t > (new Date()).getTime()) { - if (!this._drawNext()) { complete = true; break; } - } - if (complete) { - this._endBuild(); - } else { - var _this = this; - this._timerID = setTimeout(function() { _this._run(); }, 50-ts); - } - var p = this.progress = this._index/this._frames.length; - if (this.hasEventListener("progress")) { - var evt = new createjs.Event("progress"); - evt.progress = p; - this.dispatchEvent(evt); - } - }; - - /** - * @method _drawNext - * @protected - * @return Boolean Returns false if this is the last draw. - **/ - p._drawNext = function() { - var frame = this._frames[this._index]; - var sc = frame.scale*this._scale; - var rect = frame.rect; - var sourceRect = frame.sourceRect; - var canvas = this._data.images[frame.img]; - var ctx = canvas.getContext("2d"); - frame.funct&&frame.funct(frame.source, frame.data); - ctx.save(); - ctx.beginPath(); - ctx.rect(rect.x, rect.y, rect.width, rect.height); - ctx.clip(); - ctx.translate(Math.ceil(rect.x-sourceRect.x*sc), Math.ceil(rect.y-sourceRect.y*sc)); - ctx.scale(sc,sc); - frame.source.draw(ctx); // display object will draw itself. - ctx.restore(); - return (++this._index) < this._frames.length; - }; - - - createjs.SpriteSheetBuilder = createjs.promote(SpriteSheetBuilder, "EventDispatcher"); -}()); - -//############################################################################## -// DOMElement.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * This class is still experimental, and more advanced use is likely to be buggy. Please report bugs. - * - * A DOMElement allows you to associate a HTMLElement with the display list. It will be transformed - * within the DOM as though it is child of the {{#crossLink "Container"}}{{/crossLink}} it is added to. However, it is - * not rendered to canvas, and as such will retain whatever z-index it has relative to the canvas (ie. it will be - * drawn in front of or behind the canvas). - * - * The position of a DOMElement is relative to their parent node in the DOM. It is recommended that - * the DOM Object be added to a div that also contains the canvas so that they share the same position - * on the page. - * - * DOMElement is useful for positioning HTML elements over top of canvas content, and for elements - * that you want to display outside the bounds of the canvas. For example, a tooltip with rich HTML - * content. - * - *

    Mouse Interaction

    - * - * DOMElement instances are not full EaselJS display objects, and do not participate in EaselJS mouse - * events or support methods like hitTest. To get mouse events from a DOMElement, you must instead add handlers to - * the htmlElement (note, this does not support EventDispatcher) - * - * var domElement = new createjs.DOMElement(htmlElement); - * domElement.htmlElement.onclick = function() { - * console.log("clicked"); - * } - * - * @class DOMElement - * @extends DisplayObject - * @constructor - * @param {HTMLElement} htmlElement A reference or id for the DOM element to manage. - */ - function DOMElement(htmlElement) { - this.DisplayObject_constructor(); - - if (typeof(htmlElement)=="string") { htmlElement = document.getElementById(htmlElement); } - this.mouseEnabled = false; - - var style = htmlElement.style; - style.position = "absolute"; - style.transformOrigin = style.WebkitTransformOrigin = style.msTransformOrigin = style.MozTransformOrigin = style.OTransformOrigin = "0% 0%"; - - - // public properties: - /** - * The DOM object to manage. - * @property htmlElement - * @type HTMLElement - */ - this.htmlElement = htmlElement; - - - // private properties: - /** - * @property _oldMtx - * @type Matrix2D - * @protected - */ - this._oldProps = null; - } - var p = createjs.extend(DOMElement, createjs.DisplayObject); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** - * Returns true or false indicating whether the display object would be visible if drawn to a canvas. - * This does not account for whether it would be visible within the boundaries of the stage. - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method isVisible - * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas - */ - p.isVisible = function() { - return this.htmlElement != null; - }; - - /** - * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform. - * Returns true if the draw was handled (useful for overriding functionality). - * NOTE: This method is mainly for internal use, though it may be useful for advanced uses. - * @method draw - * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into. - * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache. - * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back - * into itself). - * @return {Boolean} - */ - p.draw = function(ctx, ignoreCache) { - // this relies on the _tick method because draw isn't called if the parent is not visible. - // the actual update happens in _handleDrawEnd - return true; - }; - - /** - * Not applicable to DOMElement. - * @method cache - */ - p.cache = function() {}; - - /** - * Not applicable to DOMElement. - * @method uncache - */ - p.uncache = function() {}; - - /** - * Not applicable to DOMElement. - * @method updateCache - */ - p.updateCache = function() {}; - - /** - * Not applicable to DOMElement. - * @method hitTest - */ - p.hitTest = function() {}; - - /** - * Not applicable to DOMElement. - * @method localToGlobal - */ - p.localToGlobal = function() {}; - - /** - * Not applicable to DOMElement. - * @method globalToLocal - */ - p.globalToLocal = function() {}; - - /** - * Not applicable to DOMElement. - * @method localToLocal - */ - p.localToLocal = function() {}; - - /** - * DOMElement cannot be cloned. Throws an error. - * @method clone - */ - p.clone = function() { - throw("DOMElement cannot be cloned.") - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - */ - p.toString = function() { - return "[DOMElement (name="+ this.name +")]"; - }; - - /** - * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances - * are not full EaselJS display objects and do not participate in EaselJS mouse events. - * @event click - */ - - /** - * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances - * are not full EaselJS display objects and do not participate in EaselJS mouse events. - * @event dblClick - */ - - /** - * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances - * are not full EaselJS display objects and do not participate in EaselJS mouse events. - * @event mousedown - */ - - /** - * The HTMLElement can listen for the mouseover event, not the DOMElement instance. - * Since DOMElement instances are not full EaselJS display objects and do not participate in EaselJS mouse events. - * @event mouseover - */ - - /** - * Not applicable to DOMElement. - * @event tick - */ - - -// private methods: - /** - * @method _tick - * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs. - * function. - * @protected - */ - p._tick = function(evtObj) { - var stage = this.getStage(); - stage&&stage.on("drawend", this._handleDrawEnd, this, true); - this.DisplayObject__tick(evtObj); - }; - - /** - * @method _handleDrawEnd - * @param {Event} evt - * @protected - */ - p._handleDrawEnd = function(evt) { - var o = this.htmlElement; - if (!o) { return; } - var style = o.style; - - var props = this.getConcatenatedDisplayProps(this._props), mtx = props.matrix; - - var visibility = props.visible ? "visible" : "hidden"; - if (visibility != style.visibility) { style.visibility = visibility; } - if (!props.visible) { return; } - - var oldProps = this._oldProps, oldMtx = oldProps&&oldProps.matrix; - var n = 10000; // precision - - if (!oldMtx || !oldMtx.equals(mtx)) { - var str = "matrix(" + (mtx.a*n|0)/n +","+ (mtx.b*n|0)/n +","+ (mtx.c*n|0)/n +","+ (mtx.d*n|0)/n +","+ (mtx.tx+0.5|0); - style.transform = style.WebkitTransform = style.OTransform = style.msTransform = str +","+ (mtx.ty+0.5|0) +")"; - style.MozTransform = str +"px,"+ (mtx.ty+0.5|0) +"px)"; - if (!oldProps) { oldProps = this._oldProps = new createjs.DisplayProps(true, NaN); } - oldProps.matrix.copy(mtx); - } - - if (oldProps.alpha != props.alpha) { - style.opacity = ""+(props.alpha*n|0)/n; - oldProps.alpha = props.alpha; - } - }; - - - createjs.DOMElement = createjs.promote(DOMElement, "DisplayObject"); -}()); - -//############################################################################## -// Filter.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Base class that all filters should inherit from. Filters need to be applied to objects that have been cached using - * the {{#crossLink "DisplayObject/cache"}}{{/crossLink}} method. If an object changes, please cache it again, or use - * {{#crossLink "DisplayObject/updateCache"}}{{/crossLink}}. Note that the filters must be applied before caching. - * - *

    Example

    - * - * myInstance.filters = [ - * new createjs.ColorFilter(0, 0, 0, 1, 255, 0, 0), - * new createjs.BlurFilter(5, 5, 10) - * ]; - * myInstance.cache(0,0, 100, 100); - * - * Note that each filter can implement a {{#crossLink "Filter/getBounds"}}{{/crossLink}} method, which returns the - * margins that need to be applied in order to fully display the filter. For example, the {{#crossLink "BlurFilter"}}{{/crossLink}} - * will cause an object to feather outwards, resulting in a margin around the shape. - * - *

    EaselJS Filters

    - * EaselJS comes with a number of pre-built filters: - *
    • {{#crossLink "AlphaMapFilter"}}{{/crossLink}} : Map a greyscale image to the alpha channel of a display object
    • - *
    • {{#crossLink "AlphaMaskFilter"}}{{/crossLink}}: Map an image's alpha channel to the alpha channel of a display object
    • - *
    • {{#crossLink "BlurFilter"}}{{/crossLink}}: Apply vertical and horizontal blur to a display object
    • - *
    • {{#crossLink "ColorFilter"}}{{/crossLink}}: Color transform a display object
    • - *
    • {{#crossLink "ColorMatrixFilter"}}{{/crossLink}}: Transform an image using a {{#crossLink "ColorMatrix"}}{{/crossLink}}
    • - *
    - * - * @class Filter - * @constructor - **/ - function Filter() {} - var p = Filter.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// public methods: - /** - * Provides padding values for this filter. That is, how much the filter will extend the visual bounds of an object it is applied to. - * @method getBounds - * @param {Rectangle} [rect] If specified, the provided Rectangle instance will be expanded by the padding amounts and returned. - * @return {Rectangle} If a `rect` param was provided, it is returned. If not, either a new rectangle with the padding values, or null if no padding is required for this filter. - **/ - p.getBounds = function(rect) { - return rect; - }; - - /** - * Applies the filter to the specified context. - * @method applyFilter - * @param {CanvasRenderingContext2D} ctx The 2D context to use as the source. - * @param {Number} x The x position to use for the source rect. - * @param {Number} y The y position to use for the source rect. - * @param {Number} width The width to use for the source rect. - * @param {Number} height The height to use for the source rect. - * @param {CanvasRenderingContext2D} [targetCtx] The 2D context to draw the result to. Defaults to the context passed to ctx. - * @param {Number} [targetX] The x position to draw the result to. Defaults to the value passed to x. - * @param {Number} [targetY] The y position to draw the result to. Defaults to the value passed to y. - * @return {Boolean} If the filter was applied successfully. - **/ - p.applyFilter = function(ctx, x, y, width, height, targetCtx, targetX, targetY) { - // this is the default behaviour because most filters access pixel data. It is overridden when not needed. - targetCtx = targetCtx || ctx; - if (targetX == null) { targetX = x; } - if (targetY == null) { targetY = y; } - try { - var imageData = ctx.getImageData(x, y, width, height); - } catch (e) { - return false; - } - if (this._applyFilter(imageData)) { - targetCtx.putImageData(imageData, targetX, targetY); - return true; - } - return false; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Filter]"; - }; - - /** - * Returns a clone of this Filter instance. - * @method clone - * @return {Filter} A clone of the current Filter instance. - **/ - p.clone = function() { - return new Filter(); - }; - -// private methods: - /** - * @method _applyFilter - * @param {ImageData} imageData Target ImageData instance. - * @return {Boolean} - **/ - p._applyFilter = function(imageData) { return true; }; - - - createjs.Filter = Filter; -}()); - -//############################################################################## -// BlurFilter.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Applies a box blur to DisplayObjects. Note that this filter is fairly CPU intensive, particularly if the quality is - * set higher than 1. - * - *

    Example

    - * This example creates a red circle, and then applies a 5 pixel blur to it. It uses the {{#crossLink "Filter/getBounds"}}{{/crossLink}} - * method to account for the spread that the blur causes. - * - * var shape = new createjs.Shape().set({x:100,y:100}); - * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50); - * - * var blurFilter = new createjs.BlurFilter(5, 5, 1); - * shape.filters = [blurFilter]; - * var bounds = blurFilter.getBounds(); - * - * shape.cache(-50+bounds.x, -50+bounds.y, 100+bounds.width, 100+bounds.height); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters. - * @class BlurFilter - * @extends Filter - * @constructor - * @param {Number} [blurX=0] The horizontal blur radius in pixels. - * @param {Number} [blurY=0] The vertical blur radius in pixels. - * @param {Number} [quality=1] The number of blur iterations. - **/ - function BlurFilter( blurX, blurY, quality) { - if ( isNaN(blurX) || blurX < 0 ) blurX = 0; - if ( isNaN(blurY) || blurY < 0 ) blurY = 0; - if ( isNaN(quality) || quality < 1 ) quality = 1; - - - // public properties: - /** - * Horizontal blur radius in pixels - * @property blurX - * @default 0 - * @type Number - **/ - this.blurX = blurX | 0; - - /** - * Vertical blur radius in pixels - * @property blurY - * @default 0 - * @type Number - **/ - this.blurY = blurY | 0; - - /** - * Number of blur iterations. For example, a value of 1 will produce a rough blur. A value of 2 will produce a - * smoother blur, but take twice as long to run. - * @property quality - * @default 1 - * @type Number - **/ - this.quality = quality | 0; - } - var p = createjs.extend(BlurFilter, createjs.Filter); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// constants: - /** - * Array of multiply values for blur calculations. - * @property MUL_TABLE - * @type Array - * @protected - * @static - **/ - BlurFilter.MUL_TABLE = [1, 171, 205, 293, 57, 373, 79, 137, 241, 27, 391, 357, 41, 19, 283, 265, 497, 469, 443, 421, 25, 191, 365, 349, 335, 161, 155, 149, 9, 278, 269, 261, 505, 245, 475, 231, 449, 437, 213, 415, 405, 395, 193, 377, 369, 361, 353, 345, 169, 331, 325, 319, 313, 307, 301, 37, 145, 285, 281, 69, 271, 267, 263, 259, 509, 501, 493, 243, 479, 118, 465, 459, 113, 446, 55, 435, 429, 423, 209, 413, 51, 403, 199, 393, 97, 3, 379, 375, 371, 367, 363, 359, 355, 351, 347, 43, 85, 337, 333, 165, 327, 323, 5, 317, 157, 311, 77, 305, 303, 75, 297, 294, 73, 289, 287, 71, 141, 279, 277, 275, 68, 135, 67, 133, 33, 262, 260, 129, 511, 507, 503, 499, 495, 491, 61, 121, 481, 477, 237, 235, 467, 232, 115, 457, 227, 451, 7, 445, 221, 439, 218, 433, 215, 427, 425, 211, 419, 417, 207, 411, 409, 203, 202, 401, 399, 396, 197, 49, 389, 387, 385, 383, 95, 189, 47, 187, 93, 185, 23, 183, 91, 181, 45, 179, 89, 177, 11, 175, 87, 173, 345, 343, 341, 339, 337, 21, 167, 83, 331, 329, 327, 163, 81, 323, 321, 319, 159, 79, 315, 313, 39, 155, 309, 307, 153, 305, 303, 151, 75, 299, 149, 37, 295, 147, 73, 291, 145, 289, 287, 143, 285, 71, 141, 281, 35, 279, 139, 69, 275, 137, 273, 17, 271, 135, 269, 267, 133, 265, 33, 263, 131, 261, 130, 259, 129, 257, 1]; - - /** - * Array of shift values for blur calculations. - * @property SHG_TABLE - * @type Array - * @protected - * @static - **/ - BlurFilter.SHG_TABLE = [0, 9, 10, 11, 9, 12, 10, 11, 12, 9, 13, 13, 10, 9, 13, 13, 14, 14, 14, 14, 10, 13, 14, 14, 14, 13, 13, 13, 9, 14, 14, 14, 15, 14, 15, 14, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 12, 14, 15, 15, 13, 15, 15, 15, 15, 16, 16, 16, 15, 16, 14, 16, 16, 14, 16, 13, 16, 16, 16, 15, 16, 13, 16, 15, 16, 14, 9, 16, 16, 16, 16, 16, 16, 16, 16, 16, 13, 14, 16, 16, 15, 16, 16, 10, 16, 15, 16, 14, 16, 16, 14, 16, 16, 14, 16, 16, 14, 15, 16, 16, 16, 14, 15, 14, 15, 13, 16, 16, 15, 17, 17, 17, 17, 17, 17, 14, 15, 17, 17, 16, 16, 17, 16, 15, 17, 16, 17, 11, 17, 16, 17, 16, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 16, 17, 17, 17, 16, 14, 17, 17, 17, 17, 15, 16, 14, 16, 15, 16, 13, 16, 15, 16, 14, 16, 15, 16, 12, 16, 15, 16, 17, 17, 17, 17, 17, 13, 16, 15, 17, 17, 17, 16, 15, 17, 17, 17, 16, 15, 17, 17, 14, 16, 17, 17, 16, 17, 17, 16, 15, 17, 16, 14, 17, 16, 15, 17, 16, 17, 17, 16, 17, 15, 16, 17, 14, 17, 16, 15, 17, 16, 17, 13, 17, 16, 17, 17, 16, 17, 14, 17, 16, 17, 16, 17, 16, 17, 9]; - -// public methods: - /** docced in super class **/ - p.getBounds = function (rect) { - var x = this.blurX|0, y = this.blurY| 0; - if (x <= 0 && y <= 0) { return rect; } - var q = Math.pow(this.quality, 0.2); - return (rect || new createjs.Rectangle()).pad(x*q+1,y*q+1,x*q+1,y*q+1); - }; - - /** docced in super class **/ - p.clone = function() { - return new BlurFilter(this.blurX, this.blurY, this.quality); - }; - - /** docced in super class **/ - p.toString = function() { - return "[BlurFilter]"; - }; - - -// private methods: - - /** docced in super class **/ - p._applyFilter = function (imageData) { - - var radiusX = this.blurX >> 1; - if (isNaN(radiusX) || radiusX < 0) return false; - var radiusY = this.blurY >> 1; - if (isNaN(radiusY) || radiusY < 0) return false; - if (radiusX == 0 && radiusY == 0) return false; - - var iterations = this.quality; - if (isNaN(iterations) || iterations < 1) iterations = 1; - iterations |= 0; - if (iterations > 3) iterations = 3; - if (iterations < 1) iterations = 1; - - var px = imageData.data; - var x=0, y=0, i=0, p=0, yp=0, yi=0, yw=0, r=0, g=0, b=0, a=0, pr=0, pg=0, pb=0, pa=0; - - var divx = (radiusX + radiusX + 1) | 0; - var divy = (radiusY + radiusY + 1) | 0; - var w = imageData.width | 0; - var h = imageData.height | 0; - - var w1 = (w - 1) | 0; - var h1 = (h - 1) | 0; - var rxp1 = (radiusX + 1) | 0; - var ryp1 = (radiusY + 1) | 0; - - var ssx = {r:0,b:0,g:0,a:0}; - var sx = ssx; - for ( i = 1; i < divx; i++ ) - { - sx = sx.n = {r:0,b:0,g:0,a:0}; - } - sx.n = ssx; - - var ssy = {r:0,b:0,g:0,a:0}; - var sy = ssy; - for ( i = 1; i < divy; i++ ) - { - sy = sy.n = {r:0,b:0,g:0,a:0}; - } - sy.n = ssy; - - var si = null; - - - var mtx = BlurFilter.MUL_TABLE[radiusX] | 0; - var stx = BlurFilter.SHG_TABLE[radiusX] | 0; - var mty = BlurFilter.MUL_TABLE[radiusY] | 0; - var sty = BlurFilter.SHG_TABLE[radiusY] | 0; - - while (iterations-- > 0) { - - yw = yi = 0; - var ms = mtx; - var ss = stx; - for (y = h; --y > -1;) { - r = rxp1 * (pr = px[(yi) | 0]); - g = rxp1 * (pg = px[(yi + 1) | 0]); - b = rxp1 * (pb = px[(yi + 2) | 0]); - a = rxp1 * (pa = px[(yi + 3) | 0]); - - sx = ssx; - - for( i = rxp1; --i > -1; ) - { - sx.r = pr; - sx.g = pg; - sx.b = pb; - sx.a = pa; - sx = sx.n; - } - - for( i = 1; i < rxp1; i++ ) - { - p = (yi + ((w1 < i ? w1 : i) << 2)) | 0; - r += ( sx.r = px[p]); - g += ( sx.g = px[p+1]); - b += ( sx.b = px[p+2]); - a += ( sx.a = px[p+3]); - - sx = sx.n; - } - - si = ssx; - for ( x = 0; x < w; x++ ) - { - px[yi++] = (r * ms) >>> ss; - px[yi++] = (g * ms) >>> ss; - px[yi++] = (b * ms) >>> ss; - px[yi++] = (a * ms) >>> ss; - - p = ((yw + ((p = x + radiusX + 1) < w1 ? p : w1)) << 2); - - r -= si.r - ( si.r = px[p]); - g -= si.g - ( si.g = px[p+1]); - b -= si.b - ( si.b = px[p+2]); - a -= si.a - ( si.a = px[p+3]); - - si = si.n; - - } - yw += w; - } - - ms = mty; - ss = sty; - for (x = 0; x < w; x++) { - yi = (x << 2) | 0; - - r = (ryp1 * (pr = px[yi])) | 0; - g = (ryp1 * (pg = px[(yi + 1) | 0])) | 0; - b = (ryp1 * (pb = px[(yi + 2) | 0])) | 0; - a = (ryp1 * (pa = px[(yi + 3) | 0])) | 0; - - sy = ssy; - for( i = 0; i < ryp1; i++ ) - { - sy.r = pr; - sy.g = pg; - sy.b = pb; - sy.a = pa; - sy = sy.n; - } - - yp = w; - - for( i = 1; i <= radiusY; i++ ) - { - yi = ( yp + x ) << 2; - - r += ( sy.r = px[yi]); - g += ( sy.g = px[yi+1]); - b += ( sy.b = px[yi+2]); - a += ( sy.a = px[yi+3]); - - sy = sy.n; - - if( i < h1 ) - { - yp += w; - } - } - - yi = x; - si = ssy; - if ( iterations > 0 ) - { - for ( y = 0; y < h; y++ ) - { - p = yi << 2; - px[p+3] = pa =(a * ms) >>> ss; - if ( pa > 0 ) - { - px[p] = ((r * ms) >>> ss ); - px[p+1] = ((g * ms) >>> ss ); - px[p+2] = ((b * ms) >>> ss ); - } else { - px[p] = px[p+1] = px[p+2] = 0 - } - - p = ( x + (( ( p = y + ryp1) < h1 ? p : h1 ) * w )) << 2; - - r -= si.r - ( si.r = px[p]); - g -= si.g - ( si.g = px[p+1]); - b -= si.b - ( si.b = px[p+2]); - a -= si.a - ( si.a = px[p+3]); - - si = si.n; - - yi += w; - } - } else { - for ( y = 0; y < h; y++ ) - { - p = yi << 2; - px[p+3] = pa =(a * ms) >>> ss; - if ( pa > 0 ) - { - pa = 255 / pa; - px[p] = ((r * ms) >>> ss ) * pa; - px[p+1] = ((g * ms) >>> ss ) * pa; - px[p+2] = ((b * ms) >>> ss ) * pa; - } else { - px[p] = px[p+1] = px[p+2] = 0 - } - - p = ( x + (( ( p = y + ryp1) < h1 ? p : h1 ) * w )) << 2; - - r -= si.r - ( si.r = px[p]); - g -= si.g - ( si.g = px[p+1]); - b -= si.b - ( si.b = px[p+2]); - a -= si.a - ( si.a = px[p+3]); - - si = si.n; - - yi += w; - } - } - } - - } - return true; - }; - - createjs.BlurFilter = createjs.promote(BlurFilter, "Filter"); -}()); - -//############################################################################## -// AlphaMapFilter.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - -// constructor: - /** - * Applies a greyscale alpha map image (or canvas) to the target, such that the alpha channel of the result will - * be copied from the red channel of the map, and the RGB channels will be copied from the target. - * - * Generally, it is recommended that you use {{#crossLink "AlphaMaskFilter"}}{{/crossLink}}, because it has much - * better performance. - * - *

    Example

    - * This example draws a red->blue box, caches it, and then uses the cache canvas as an alpha map on a 100x100 image. - * - * var box = new createjs.Shape(); - * box.graphics.beginLinearGradientFill(["#ff0000", "#0000ff"], [0, 1], 0, 0, 0, 100) - * box.graphics.drawRect(0, 0, 100, 100); - * box.cache(0, 0, 100, 100); - * - * var bmp = new createjs.Bitmap("path/to/image.jpg"); - * bmp.filters = [ - * new createjs.AlphaMapFilter(box.cacheCanvas) - * ]; - * bmp.cache(0, 0, 100, 100); - * stage.addChild(bmp); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for more information on applying filters. - * @class AlphaMapFilter - * @extends Filter - * @constructor - * @param {HTMLImageElement|HTMLCanvasElement} alphaMap The greyscale image (or canvas) to use as the alpha value for the - * result. This should be exactly the same dimensions as the target. - **/ - function AlphaMapFilter(alphaMap) { - - - // public properties: - /** - * The greyscale image (or canvas) to use as the alpha value for the result. This should be exactly the same - * dimensions as the target. - * @property alphaMap - * @type HTMLImageElement|HTMLCanvasElement - **/ - this.alphaMap = alphaMap; - - - // private properties: - /** - * @property _alphaMap - * @protected - * @type HTMLImageElement|HTMLCanvasElement - **/ - this._alphaMap = null; - - /** - * @property _mapData - * @protected - * @type Uint8ClampedArray - **/ - this._mapData = null; - } - var p = createjs.extend(AlphaMapFilter, createjs.Filter); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** docced in super class **/ - p.clone = function () { - var o = new AlphaMapFilter(this.alphaMap); - o._alphaMap = this._alphaMap; - o._mapData = this._mapData; - return o; - }; - - /** docced in super class **/ - p.toString = function () { - return "[AlphaMapFilter]"; - }; - - -// private methods: - /** docced in super class **/ - p._applyFilter = function (imageData) { - if (!this.alphaMap) { return true; } - if (!this._prepAlphaMap()) { return false; } - - // TODO: update to support scenarios where the target has different dimensions. - var data = imageData.data; - var map = this._mapData; - for(var i=0, l=data.length; iIMPORTANT NOTE: This filter currently does not support the targetCtx, or targetX/Y parameters correctly. - * - *

    Example

    - * This example draws a gradient box, then caches it and uses the "cacheCanvas" as the alpha mask on a 100x100 image. - * - * var box = new createjs.Shape(); - * box.graphics.beginLinearGradientFill(["#000000", "rgba(0, 0, 0, 0)"], [0, 1], 0, 0, 100, 100) - * box.graphics.drawRect(0, 0, 100, 100); - * box.cache(0, 0, 100, 100); - * - * var bmp = new createjs.Bitmap("path/to/image.jpg"); - * bmp.filters = [ - * new createjs.AlphaMaskFilter(box.cacheCanvas) - * ]; - * bmp.cache(0, 0, 100, 100); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for more information on applying filters. - * @class AlphaMaskFilter - * @extends Filter - * @constructor - * @param {HTMLImageElement|HTMLCanvasElement} mask - **/ - function AlphaMaskFilter(mask) { - - - // public properties: - /** - * The image (or canvas) to use as the mask. - * @property mask - * @type HTMLImageElement|HTMLCanvasElement - **/ - this.mask = mask; - } - var p = createjs.extend(AlphaMaskFilter, createjs.Filter); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** - * Applies the filter to the specified context. - * - * IMPORTANT NOTE: This filter currently does not support the targetCtx, or targetX/Y parameters - * correctly. - * @method applyFilter - * @param {CanvasRenderingContext2D} ctx The 2D context to use as the source. - * @param {Number} x The x position to use for the source rect. - * @param {Number} y The y position to use for the source rect. - * @param {Number} width The width to use for the source rect. - * @param {Number} height The height to use for the source rect. - * @param {CanvasRenderingContext2D} [targetCtx] NOT SUPPORTED IN THIS FILTER. The 2D context to draw the result to. Defaults to the context passed to ctx. - * @param {Number} [targetX] NOT SUPPORTED IN THIS FILTER. The x position to draw the result to. Defaults to the value passed to x. - * @param {Number} [targetY] NOT SUPPORTED IN THIS FILTER. The y position to draw the result to. Defaults to the value passed to y. - * @return {Boolean} If the filter was applied successfully. - **/ - p.applyFilter = function (ctx, x, y, width, height, targetCtx, targetX, targetY) { - if (!this.mask) { return true; } - targetCtx = targetCtx || ctx; - if (targetX == null) { targetX = x; } - if (targetY == null) { targetY = y; } - - targetCtx.save(); - if (ctx != targetCtx) { - // TODO: support targetCtx and targetX/Y - // clearRect, then draw the ctx in? - return false; - } - - targetCtx.globalCompositeOperation = "destination-in"; - targetCtx.drawImage(this.mask, targetX, targetY); - targetCtx.restore(); - return true; - }; - - /** docced in super class **/ - p.clone = function () { - return new AlphaMaskFilter(this.mask); - }; - - /** docced in super class **/ - p.toString = function () { - return "[AlphaMaskFilter]"; - }; - - - createjs.AlphaMaskFilter = createjs.promote(AlphaMaskFilter, "Filter"); -}()); - -//############################################################################## -// ColorFilter.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Applies a color transform to DisplayObjects. - * - *

    Example

    - * This example draws a red circle, and then transforms it to Blue. This is accomplished by multiplying all the channels - * to 0 (except alpha, which is set to 1), and then adding 255 to the blue channel. - * - * var shape = new createjs.Shape().set({x:100,y:100}); - * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50); - * - * shape.filters = [ - * new createjs.ColorFilter(0,0,0,1, 0,0,255,0) - * ]; - * shape.cache(-50, -50, 100, 100); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters. - * @class ColorFilter - * @param {Number} [redMultiplier=1] The amount to multiply against the red channel. This is a range between 0 and 1. - * @param {Number} [greenMultiplier=1] The amount to multiply against the green channel. This is a range between 0 and 1. - * @param {Number} [blueMultiplier=1] The amount to multiply against the blue channel. This is a range between 0 and 1. - * @param {Number} [alphaMultiplier=1] The amount to multiply against the alpha channel. This is a range between 0 and 1. - * @param {Number} [redOffset=0] The amount to add to the red channel after it has been multiplied. This is a range - * between -255 and 255. - * @param {Number} [greenOffset=0] The amount to add to the green channel after it has been multiplied. This is a range - * between -255 and 255. - * @param {Number} [blueOffset=0] The amount to add to the blue channel after it has been multiplied. This is a range - * between -255 and 255. - * @param {Number} [alphaOffset=0] The amount to add to the alpha channel after it has been multiplied. This is a range - * between -255 and 255. - * @constructor - * @extends Filter - **/ - function ColorFilter(redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier, redOffset, greenOffset, blueOffset, alphaOffset) { - - - // public properties: - /** - * Red channel multiplier. - * @property redMultiplier - * @type Number - **/ - this.redMultiplier = redMultiplier != null ? redMultiplier : 1; - - /** - * Green channel multiplier. - * @property greenMultiplier - * @type Number - **/ - this.greenMultiplier = greenMultiplier != null ? greenMultiplier : 1; - - /** - * Blue channel multiplier. - * @property blueMultiplier - * @type Number - **/ - this.blueMultiplier = blueMultiplier != null ? blueMultiplier : 1; - - /** - * Alpha channel multiplier. - * @property alphaMultiplier - * @type Number - **/ - this.alphaMultiplier = alphaMultiplier != null ? alphaMultiplier : 1; - - /** - * Red channel offset (added to value). - * @property redOffset - * @type Number - **/ - this.redOffset = redOffset || 0; - - /** - * Green channel offset (added to value). - * @property greenOffset - * @type Number - **/ - this.greenOffset = greenOffset || 0; - - /** - * Blue channel offset (added to value). - * @property blueOffset - * @type Number - **/ - this.blueOffset = blueOffset || 0; - - /** - * Alpha channel offset (added to value). - * @property alphaOffset - * @type Number - **/ - this.alphaOffset = alphaOffset || 0; - } - var p = createjs.extend(ColorFilter, createjs.Filter); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** docced in super class **/ - p.toString = function() { - return "[ColorFilter]"; - }; - - /** docced in super class **/ - p.clone = function() { - return new ColorFilter(this.redMultiplier, this.greenMultiplier, this.blueMultiplier, this.alphaMultiplier, this.redOffset, this.greenOffset, this.blueOffset, this.alphaOffset); - }; - - -// private methods: - /** docced in super class **/ - p._applyFilter = function(imageData) { - var data = imageData.data; - var l = data.length; - for (var i=0; iExample - * - * myColorMatrix.adjustHue(20).adjustBrightness(50); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for an example of how to apply filters, or {{#crossLink "ColorMatrixFilter"}}{{/crossLink}} - * for an example of how to use ColorMatrix to change a DisplayObject's color. - * @class ColorMatrix - * @param {Number} brightness - * @param {Number} contrast - * @param {Number} saturation - * @param {Number} hue - * @constructor - **/ - function ColorMatrix(brightness, contrast, saturation, hue) { - this.setColor(brightness, contrast, saturation, hue); - } - var p = ColorMatrix.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// constants: - /** - * Array of delta values for contrast calculations. - * @property DELTA_INDEX - * @type Array - * @protected - * @static - **/ - ColorMatrix.DELTA_INDEX = [ - 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11, - 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24, - 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42, - 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68, - 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98, - 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54, - 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25, - 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8, - 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0, - 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8, - 10.0 - ]; - - /** - * Identity matrix values. - * @property IDENTITY_MATRIX - * @type Array - * @protected - * @static - **/ - ColorMatrix.IDENTITY_MATRIX = [ - 1,0,0,0,0, - 0,1,0,0,0, - 0,0,1,0,0, - 0,0,0,1,0, - 0,0,0,0,1 - ]; - - /** - * The constant length of a color matrix. - * @property LENGTH - * @type Number - * @protected - * @static - **/ - ColorMatrix.LENGTH = ColorMatrix.IDENTITY_MATRIX.length; - - -// public methods: - /** - * Resets the instance with the specified values. - * @method setColor - * @param {Number} brightness - * @param {Number} contrast - * @param {Number} saturation - * @param {Number} hue - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.setColor = function(brightness,contrast,saturation,hue) { - return this.reset().adjustColor(brightness,contrast,saturation,hue); - }; - - /** - * Resets the matrix to identity values. - * @method reset - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.reset = function() { - return this.copy(ColorMatrix.IDENTITY_MATRIX); - }; - - /** - * Shortcut method to adjust brightness, contrast, saturation and hue. - * Equivalent to calling adjustHue(hue), adjustContrast(contrast), - * adjustBrightness(brightness), adjustSaturation(saturation), in that order. - * @method adjustColor - * @param {Number} brightness - * @param {Number} contrast - * @param {Number} saturation - * @param {Number} hue - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.adjustColor = function(brightness,contrast,saturation,hue) { - this.adjustHue(hue); - this.adjustContrast(contrast); - this.adjustBrightness(brightness); - return this.adjustSaturation(saturation); - }; - - /** - * Adjusts the brightness of pixel color by adding the specified value to the red, green and blue channels. - * Positive values will make the image brighter, negative values will make it darker. - * @method adjustBrightness - * @param {Number} value A value between -255 & 255 that will be added to the RGB channels. - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.adjustBrightness = function(value) { - if (value == 0 || isNaN(value)) { return this; } - value = this._cleanValue(value,255); - this._multiplyMatrix([ - 1,0,0,0,value, - 0,1,0,0,value, - 0,0,1,0,value, - 0,0,0,1,0, - 0,0,0,0,1 - ]); - return this; - }; - - /** - * Adjusts the contrast of pixel color. - * Positive values will increase contrast, negative values will decrease contrast. - * @method adjustContrast - * @param {Number} value A value between -100 & 100. - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.adjustContrast = function(value) { - if (value == 0 || isNaN(value)) { return this; } - value = this._cleanValue(value,100); - var x; - if (value<0) { - x = 127+value/100*127; - } else { - x = value%1; - if (x == 0) { - x = ColorMatrix.DELTA_INDEX[value]; - } else { - x = ColorMatrix.DELTA_INDEX[(value<<0)]*(1-x)+ColorMatrix.DELTA_INDEX[(value<<0)+1]*x; // use linear interpolation for more granularity. - } - x = x*127+127; - } - this._multiplyMatrix([ - x/127,0,0,0,0.5*(127-x), - 0,x/127,0,0,0.5*(127-x), - 0,0,x/127,0,0.5*(127-x), - 0,0,0,1,0, - 0,0,0,0,1 - ]); - return this; - }; - - /** - * Adjusts the color saturation of the pixel. - * Positive values will increase saturation, negative values will decrease saturation (trend towards greyscale). - * @method adjustSaturation - * @param {Number} value A value between -100 & 100. - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.adjustSaturation = function(value) { - if (value == 0 || isNaN(value)) { return this; } - value = this._cleanValue(value,100); - var x = 1+((value > 0) ? 3*value/100 : value/100); - var lumR = 0.3086; - var lumG = 0.6094; - var lumB = 0.0820; - this._multiplyMatrix([ - lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0, - lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0, - lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0, - 0,0,0,1,0, - 0,0,0,0,1 - ]); - return this; - }; - - - /** - * Adjusts the hue of the pixel color. - * @method adjustHue - * @param {Number} value A value between -180 & 180. - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.adjustHue = function(value) { - if (value == 0 || isNaN(value)) { return this; } - value = this._cleanValue(value,180)/180*Math.PI; - var cosVal = Math.cos(value); - var sinVal = Math.sin(value); - var lumR = 0.213; - var lumG = 0.715; - var lumB = 0.072; - this._multiplyMatrix([ - lumR+cosVal*(1-lumR)+sinVal*(-lumR),lumG+cosVal*(-lumG)+sinVal*(-lumG),lumB+cosVal*(-lumB)+sinVal*(1-lumB),0,0, - lumR+cosVal*(-lumR)+sinVal*(0.143),lumG+cosVal*(1-lumG)+sinVal*(0.140),lumB+cosVal*(-lumB)+sinVal*(-0.283),0,0, - lumR+cosVal*(-lumR)+sinVal*(-(1-lumR)),lumG+cosVal*(-lumG)+sinVal*(lumG),lumB+cosVal*(1-lumB)+sinVal*(lumB),0,0, - 0,0,0,1,0, - 0,0,0,0,1 - ]); - return this; - }; - - /** - * Concatenates (multiplies) the specified matrix with this one. - * @method concat - * @param {Array} matrix An array or ColorMatrix instance. - * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.) - * @chainable - **/ - p.concat = function(matrix) { - matrix = this._fixMatrix(matrix); - if (matrix.length != ColorMatrix.LENGTH) { return this; } - this._multiplyMatrix(matrix); - return this; - }; - - /** - * Returns a clone of this ColorMatrix. - * @method clone - * @return {ColorMatrix} A clone of this ColorMatrix. - **/ - p.clone = function() { - return (new ColorMatrix()).copy(this); - }; - - /** - * Return a length 25 (5x5) array instance containing this matrix's values. - * @method toArray - * @return {Array} An array holding this matrix's values. - **/ - p.toArray = function() { - var arr = []; - for (var i= 0, l=ColorMatrix.LENGTH; i ColorMatrix.LENGTH) { - matrix = matrix.slice(0,ColorMatrix.LENGTH); - } - return matrix; - }; - - - createjs.ColorMatrix = ColorMatrix; -}()); - -//############################################################################## -// ColorMatrixFilter.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * Allows you to carry out complex color operations such as modifying saturation, brightness, or inverting. See the - * {{#crossLink "ColorMatrix"}}{{/crossLink}} for more information on changing colors. For an easier color transform, - * consider the {{#crossLink "ColorFilter"}}{{/crossLink}}. - * - *

    Example

    - * This example creates a red circle, inverts its hue, and then saturates it to brighten it up. - * - * var shape = new createjs.Shape().set({x:100,y:100}); - * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50); - * - * var matrix = new createjs.ColorMatrix().adjustHue(180).adjustSaturation(100); - * shape.filters = [ - * new createjs.ColorMatrixFilter(matrix) - * ]; - * - * shape.cache(-50, -50, 100, 100); - * - * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters. - * @class ColorMatrixFilter - * @constructor - * @extends Filter - * @param {Array | ColorMatrix} matrix A 4x5 matrix describing the color operation to perform. See also the {{#crossLink "ColorMatrix"}}{{/crossLink}} - * class. - **/ - function ColorMatrixFilter(matrix) { - - - // public properties: - /** - * A 4x5 matrix describing the color operation to perform. See also the {{#crossLink "ColorMatrix"}}{{/crossLink}} - * @property matrix - * @type Array | ColorMatrix - **/ - this.matrix = matrix; - } - var p = createjs.extend(ColorMatrixFilter, createjs.Filter); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// public methods: - /** docced in super class **/ - p.toString = function() { - return "[ColorMatrixFilter]"; - }; - - /** docced in super class **/ - p.clone = function() { - return new ColorMatrixFilter(this.matrix); - }; - -// private methods: - /** docced in super class **/ - p._applyFilter = function(imageData) { - var data = imageData.data; - var l = data.length; - var r,g,b,a; - var mtx = this.matrix; - var m0 = mtx[0], m1 = mtx[1], m2 = mtx[2], m3 = mtx[3], m4 = mtx[4]; - var m5 = mtx[5], m6 = mtx[6], m7 = mtx[7], m8 = mtx[8], m9 = mtx[9]; - var m10 = mtx[10], m11 = mtx[11], m12 = mtx[12], m13 = mtx[13], m14 = mtx[14]; - var m15 = mtx[15], m16 = mtx[16], m17 = mtx[17], m18 = mtx[18], m19 = mtx[19]; - - for (var i=0; iExample - * - * var stage = new createjs.Stage("canvasId"); - * createjs.Touch.enable(stage); - * - * Note: It is important to disable Touch on a stage that you are no longer using: - * - * createjs.Touch.disable(stage); - * - * @class Touch - * @static - **/ - function Touch() { - throw "Touch cannot be instantiated"; - } - - -// public static methods: - /** - * Returns `true` if touch is supported in the current browser. - * @method isSupported - * @return {Boolean} Indicates whether touch is supported in the current browser. - * @static - **/ - Touch.isSupported = function() { - return !!(('ontouchstart' in window) // iOS & Android - || (window.navigator['msPointerEnabled'] && window.navigator['msMaxTouchPoints'] > 0) // IE10 - || (window.navigator['pointerEnabled'] && window.navigator['maxTouchPoints'] > 0)); // IE11+ - }; - - /** - * Enables touch interaction for the specified EaselJS {{#crossLink "Stage"}}{{/crossLink}}. Currently supports iOS - * (and compatible browsers, such as modern Android browsers), and IE10/11. Supports both single touch and - * multi-touch modes. Extends the EaselJS {{#crossLink "MouseEvent"}}{{/crossLink}} model, but without support for - * double click or over/out events. See the MouseEvent {{#crossLink "MouseEvent/pointerId:property"}}{{/crossLink}} - * for more information. - * @method enable - * @param {Stage} stage The {{#crossLink "Stage"}}{{/crossLink}} to enable touch on. - * @param {Boolean} [singleTouch=false] If `true`, only a single touch will be active at a time. - * @param {Boolean} [allowDefault=false] If `true`, then default gesture actions (ex. scrolling, zooming) will be - * allowed when the user is interacting with the target canvas. - * @return {Boolean} Returns `true` if touch was successfully enabled on the target stage. - * @static - **/ - Touch.enable = function(stage, singleTouch, allowDefault) { - if (!stage || !stage.canvas || !Touch.isSupported()) { return false; } - if (stage.__touch) { return true; } - - // inject required properties on stage: - stage.__touch = {pointers:{}, multitouch:!singleTouch, preventDefault:!allowDefault, count:0}; - - // note that in the future we may need to disable the standard mouse event model before adding - // these to prevent duplicate calls. It doesn't seem to be an issue with iOS devices though. - if ('ontouchstart' in window) { Touch._IOS_enable(stage); } - else if (window.navigator['msPointerEnabled'] || window.navigator["pointerEnabled"]) { Touch._IE_enable(stage); } - return true; - }; - - /** - * Removes all listeners that were set up when calling `Touch.enable()` on a stage. - * @method disable - * @param {Stage} stage The {{#crossLink "Stage"}}{{/crossLink}} to disable touch on. - * @static - **/ - Touch.disable = function(stage) { - if (!stage) { return; } - if ('ontouchstart' in window) { Touch._IOS_disable(stage); } - else if (window.navigator['msPointerEnabled'] || window.navigator["pointerEnabled"]) { Touch._IE_disable(stage); } - - delete stage.__touch; - }; - - -// Private static methods: - /** - * @method _IOS_enable - * @protected - * @param {Stage} stage - * @static - **/ - Touch._IOS_enable = function(stage) { - var canvas = stage.canvas; - var f = stage.__touch.f = function(e) { Touch._IOS_handleEvent(stage,e); }; - canvas.addEventListener("touchstart", f, false); - canvas.addEventListener("touchmove", f, false); - canvas.addEventListener("touchend", f, false); - canvas.addEventListener("touchcancel", f, false); - }; - - /** - * @method _IOS_disable - * @protected - * @param {Stage} stage - * @static - **/ - Touch._IOS_disable = function(stage) { - var canvas = stage.canvas; - if (!canvas) { return; } - var f = stage.__touch.f; - canvas.removeEventListener("touchstart", f, false); - canvas.removeEventListener("touchmove", f, false); - canvas.removeEventListener("touchend", f, false); - canvas.removeEventListener("touchcancel", f, false); - }; - - /** - * @method _IOS_handleEvent - * @param {Stage} stage - * @param {Object} e The event to handle - * @protected - * @static - **/ - Touch._IOS_handleEvent = function(stage, e) { - if (!stage) { return; } - if (stage.__touch.preventDefault) { e.preventDefault&&e.preventDefault(); } - var touches = e.changedTouches; - var type = e.type; - for (var i= 0,l=touches.length; iExample - * - * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); - * - * @class Utility Methods - * @main Utility Methods - */ - -(function() { - "use strict"; - - /** - * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a - * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the - * method gets called in the correct scope. - * - * Additional arguments can be passed that will be applied to the function when it is called. - * - *

    Example

    - * - * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); - * - * function myHandler(arg1, arg2) { - * // This gets called when myObject.myCallback is executed. - * } - * - * @method proxy - * @param {Function} method The function to call - * @param {Object} scope The scope to call the method name on - * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. - * @public - * @static - */ - createjs.proxy = function (method, scope) { - var aArgs = Array.prototype.slice.call(arguments, 2); - return function () { - return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); - }; - } - -}()); - -//############################################################################## -// indexOf.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of - * that value. Returns -1 if value is not found. - * - * var i = createjs.indexOf(myArray, myElementToFind); - * - * @method indexOf - * @param {Array} array Array to search for searchElement - * @param searchElement Element to find in array. - * @return {Number} The first index of searchElement in array. - */ -createjs.indexOf = function (array, searchElement){ - "use strict"; - - for (var i = 0,l=array.length; i < l; i++) { - if (searchElement === array[i]) { - return i; - } - } - return -1; -}; - -//############################################################################## -// Event.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - -// constructor: - /** - * Contains properties and methods shared by all events for use with - * {{#crossLink "EventDispatcher"}}{{/crossLink}}. - * - * Note that Event objects are often reused, so you should never - * rely on an event object's state outside of the call stack it was received in. - * @class Event - * @param {String} type The event type. - * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. - * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. - * @constructor - **/ - function Event(type, bubbles, cancelable) { - - - // public properties: - /** - * The type of event. - * @property type - * @type String - **/ - this.type = type; - - /** - * The object that generated an event. - * @property target - * @type Object - * @default null - * @readonly - */ - this.target = null; - - /** - * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will - * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event - * is generated from childObj, then a listener on parentObj would receive the event with - * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). - * @property currentTarget - * @type Object - * @default null - * @readonly - */ - this.currentTarget = null; - - /** - * For bubbling events, this indicates the current event phase:
      - *
    1. capture phase: starting from the top parent to the target
    2. - *
    3. at target phase: currently being dispatched from the target
    4. - *
    5. bubbling phase: from the target to the top parent
    6. - *
    - * @property eventPhase - * @type Number - * @default 0 - * @readonly - */ - this.eventPhase = 0; - - /** - * Indicates whether the event will bubble through the display list. - * @property bubbles - * @type Boolean - * @default false - * @readonly - */ - this.bubbles = !!bubbles; - - /** - * Indicates whether the default behaviour of this event can be cancelled via - * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. - * @property cancelable - * @type Boolean - * @default false - * @readonly - */ - this.cancelable = !!cancelable; - - /** - * The epoch time at which this event was created. - * @property timeStamp - * @type Number - * @default 0 - * @readonly - */ - this.timeStamp = (new Date()).getTime(); - - /** - * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called - * on this event. - * @property defaultPrevented - * @type Boolean - * @default false - * @readonly - */ - this.defaultPrevented = false; - - /** - * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or - * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. - * @property propagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.propagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called - * on this event. - * @property immediatePropagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.immediatePropagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. - * @property removed - * @type Boolean - * @default false - * @readonly - */ - this.removed = false; - } - var p = Event.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - -// public methods: - /** - * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable. - * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will - * cancel the default behaviour associated with the event. - * @method preventDefault - **/ - p.preventDefault = function() { - this.defaultPrevented = this.cancelable&&true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopPropagation - **/ - p.stopPropagation = function() { - this.propagationStopped = true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and - * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopImmediatePropagation - **/ - p.stopImmediatePropagation = function() { - this.immediatePropagationStopped = this.propagationStopped = true; - }; - - /** - * Causes the active listener to be removed via removeEventListener(); - * - * myBtn.addEventListener("click", function(evt) { - * // do stuff... - * evt.remove(); // removes this listener. - * }); - * - * @method remove - **/ - p.remove = function() { - this.removed = true; - }; - - /** - * Returns a clone of the Event instance. - * @method clone - * @return {Event} a clone of the Event instance. - **/ - p.clone = function() { - return new Event(this.type, this.bubbles, this.cancelable); - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - * @method set - * @param {Object} props A generic object containing properties to copy to the instance. - * @return {Event} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Event (type="+this.type+")]"; - }; - - createjs.Event = Event; -}()); - -//############################################################################## -// ErrorEvent.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - /** - * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details. - * @class ErrorEvent - * @param {String} [title] The error title - * @param {String} [message] The error description - * @param {Object} [data] Additional error data - * @constructor - */ - function ErrorEvent(title, message, data) { - this.Event_constructor("error"); - - /** - * The short error title, which indicates the type of error that occurred. - * @property title - * @type String - */ - this.title = title; - - /** - * The verbose error message, containing details about the error. - * @property message - * @type String - */ - this.message = message; - - /** - * Additional data attached to an error. - * @property data - * @type {Object} - */ - this.data = data; - } - - var p = createjs.extend(ErrorEvent, createjs.Event); - - p.clone = function() { - return new createjs.ErrorEvent(this.title, this.message, this.data); - }; - - createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event"); - -}()); - -//############################################################################## -// EventDispatcher.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * EventDispatcher provides methods for managing queues of event listeners and dispatching events. - * - * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the - * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. - * - * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the - * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports - * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. - * - * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier - * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The - * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to - * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. - * - * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} - * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also - * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. - * - *

    Example

    - * Add EventDispatcher capabilities to the "MyClass" class. - * - * EventDispatcher.initialize(MyClass.prototype); - * - * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). - * - * instance.addEventListener("eventName", handlerMethod); - * function handlerMethod(event) { - * console.log(event.target + " Was Clicked"); - * } - * - * Maintaining proper scope
    - * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} - * method to subscribe to events simplifies this. - * - * instance.addEventListener("click", function(event) { - * console.log(instance == this); // false, scope is ambiguous. - * }); - * - * instance.on("click", function(event) { - * console.log(instance == this); // true, "on" uses dispatcher scope by default. - * }); - * - * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage - * scope. - * - * Browser support - * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model - * requires modern browsers (IE9+). - * - * - * @class EventDispatcher - * @constructor - **/ - function EventDispatcher() { - - - // private properties: - /** - * @protected - * @property _listeners - * @type Object - **/ - this._listeners = null; - - /** - * @protected - * @property _captureListeners - * @type Object - **/ - this._captureListeners = null; - } - var p = EventDispatcher.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// static public methods: - /** - * Static initializer to mix EventDispatcher methods into a target object or prototype. - * - * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class - * EventDispatcher.initialize(myObject); // add to a specific instance - * - * @method initialize - * @static - * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a - * prototype. - **/ - EventDispatcher.initialize = function(target) { - target.addEventListener = p.addEventListener; - target.on = p.on; - target.removeEventListener = target.off = p.removeEventListener; - target.removeAllEventListeners = p.removeAllEventListeners; - target.hasEventListener = p.hasEventListener; - target.dispatchEvent = p.dispatchEvent; - target._dispatchEvent = p._dispatchEvent; - target.willTrigger = p.willTrigger; - }; - - -// public methods: - /** - * Adds the specified event listener. Note that adding multiple listeners to the same function will result in - * multiple callbacks getting fired. - * - *

    Example

    - * - * displayObject.addEventListener("click", handleClick); - * function handleClick(event) { - * // Click happened. - * } - * - * @method addEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function | Object} Returns the listener for chaining or assignment. - **/ - p.addEventListener = function(type, listener, useCapture) { - var listeners; - if (useCapture) { - listeners = this._captureListeners = this._captureListeners||{}; - } else { - listeners = this._listeners = this._listeners||{}; - } - var arr = listeners[type]; - if (arr) { this.removeEventListener(type, listener, useCapture); } - arr = listeners[type]; // remove may have deleted the array - if (!arr) { listeners[type] = [listener]; } - else { arr.push(listener); } - return listener; - }; - - /** - * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener - * only run once, associate arbitrary data with the listener, and remove the listener. - * - * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. - * The wrapper function is returned for use with `removeEventListener` (or `off`). - * - * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use - * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls - * to `on` with the same params will create multiple listeners. - * - *

    Example

    - * - * var listener = myBtn.on("click", handleClick, null, false, {count:3}); - * function handleClick(evt, data) { - * data.count -= 1; - * console.log(this == myBtn); // true - scope defaults to the dispatcher - * if (data.count == 0) { - * alert("clicked 3 times!"); - * myBtn.off("click", listener); - * // alternately: evt.remove(); - * } - * } - * - * @method on - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). - * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. - * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. - * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. - **/ - p.on = function(type, listener, scope, once, data, useCapture) { - if (listener.handleEvent) { - scope = scope||listener; - listener = listener.handleEvent; - } - scope = scope||this; - return this.addEventListener(type, function(evt) { - listener.call(scope, evt, data); - once&&evt.remove(); - }, useCapture); - }; - - /** - * Removes the specified event listener. - * - * Important Note: that you must pass the exact function reference used when the event was added. If a proxy - * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or - * closure will not work. - * - *

    Example

    - * - * displayObject.removeEventListener("click", handleClick); - * - * @method removeEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.removeEventListener = function(type, listener, useCapture) { - var listeners = useCapture ? this._captureListeners : this._listeners; - if (!listeners) { return; } - var arr = listeners[type]; - if (!arr) { return; } - for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See - * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example. - * - * @method off - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.off = p.removeEventListener; - - /** - * Removes all listeners for the specified type, or all listeners of all types. - * - *

    Example

    - * - * // Remove all listeners - * displayObject.removeAllEventListeners(); - * - * // Remove all click listeners - * displayObject.removeAllEventListeners("click"); - * - * @method removeAllEventListeners - * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. - **/ - p.removeAllEventListeners = function(type) { - if (!type) { this._listeners = this._captureListeners = null; } - else { - if (this._listeners) { delete(this._listeners[type]); } - if (this._captureListeners) { delete(this._captureListeners[type]); } - } - }; - - /** - * Dispatches the specified event to all listeners. - * - *

    Example

    - * - * // Use a string event - * this.dispatchEvent("complete"); - * - * // Use an Event instance - * var event = new createjs.Event("progress"); - * this.dispatchEvent(event); - * - * @method dispatchEvent - * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. - * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, - * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can - * be used to avoid event object instantiation for non-bubbling events that may not have any listeners. - * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj. - * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj. - * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise. - **/ - p.dispatchEvent = function(eventObj, bubbles, cancelable) { - if (typeof eventObj == "string") { - // skip everything if there's no listeners and it doesn't bubble: - var listeners = this._listeners; - if (!bubbles && (!listeners || !listeners[eventObj])) { return true; } - eventObj = new createjs.Event(eventObj, bubbles, cancelable); - } else if (eventObj.target && eventObj.clone) { - // redispatching an active event object, so clone it: - eventObj = eventObj.clone(); - } - - // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent - try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events - - if (!eventObj.bubbles || !this.parent) { - this._dispatchEvent(eventObj, 2); - } else { - var top=this, list=[top]; - while (top.parent) { list.push(top = top.parent); } - var i, l=list.length; - - // capture & atTarget - for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) { - list[i]._dispatchEvent(eventObj, 1+(i==0)); - } - // bubbling - for (i=1; i= 10.53. - isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 && - // Safari < 2.0.2 stores the internal millisecond time value correctly, - // but clips the values returned by the date methods to the range of - // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]). - isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708; - } catch (exception) {} - - // Internal: Determines whether the native `JSON.stringify` and `parse` - // implementations are spec-compliant. Based on work by Ken Snyder. - function has(name) { - if (has[name] !== undef) { - // Return cached feature test result. - return has[name]; - } - var isSupported; - if (name == "bug-string-char-index") { - // IE <= 7 doesn't support accessing string characters using square - // bracket notation. IE 8 only supports this for primitives. - isSupported = "a"[0] != "a"; - } else if (name == "json") { - // Indicates whether both `JSON.stringify` and `JSON.parse` are - // supported. - isSupported = has("json-stringify") && has("json-parse"); - } else { - var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'; - // Test `JSON.stringify`. - if (name == "json-stringify") { - var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended; - if (stringifySupported) { - // A test function object with a custom `toJSON` method. - (value = function () { - return 1; - }).toJSON = value; - try { - stringifySupported = - // Firefox 3.1b1 and b2 serialize string, number, and boolean - // primitives as object literals. - stringify(0) === "0" && - // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object - // literals. - stringify(new Number()) === "0" && - stringify(new String()) == '""' && - // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or - // does not define a canonical JSON representation (this applies to - // objects with `toJSON` properties as well, *unless* they are nested - // within an object or array). - stringify(getClass) === undef && - // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and - // FF 3.1b3 pass this test. - stringify(undef) === undef && - // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s, - // respectively, if the value is omitted entirely. - stringify() === undef && - // FF 3.1b1, 2 throw an error if the given value is not a number, - // string, array, object, Boolean, or `null` literal. This applies to - // objects with custom `toJSON` methods as well, unless they are nested - // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON` - // methods entirely. - stringify(value) === "1" && - stringify([value]) == "[1]" && - // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of - // `"[null]"`. - stringify([undef]) == "[null]" && - // YUI 3.0.0b1 fails to serialize `null` literals. - stringify(null) == "null" && - // FF 3.1b1, 2 halts serialization if an array contains a function: - // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3 - // elides non-JSON values from objects and arrays, unless they - // define custom `toJSON` methods. - stringify([undef, getClass, null]) == "[null,null,null]" && - // Simple serialization test. FF 3.1b1 uses Unicode escape sequences - // where character escape codes are expected (e.g., `\b` => `\u0008`). - stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized && - // FF 3.1b1 and b2 ignore the `filter` and `width` arguments. - stringify(null, value) === "1" && - stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" && - // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly - // serialize extended years. - stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' && - // The milliseconds are optional in ES 5, but required in 5.1. - stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' && - // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative - // four-digit years instead of six-digit years. Credits: @Yaffle. - stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' && - // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond - // values less than 1000. Credits: @Yaffle. - stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"'; - } catch (exception) { - stringifySupported = false; - } - } - isSupported = stringifySupported; - } - // Test `JSON.parse`. - if (name == "json-parse") { - var parse = exports.parse; - if (typeof parse == "function") { - try { - // FF 3.1b1, b2 will throw an exception if a bare literal is provided. - // Conforming implementations should also coerce the initial argument to - // a string prior to parsing. - if (parse("0") === 0 && !parse(false)) { - // Simple parsing test. - value = parse(serialized); - var parseSupported = value["a"].length == 5 && value["a"][0] === 1; - if (parseSupported) { - try { - // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings. - parseSupported = !parse('"\t"'); - } catch (exception) {} - if (parseSupported) { - try { - // FF 4.0 and 4.0.1 allow leading `+` signs and leading - // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow - // certain octal literals. - parseSupported = parse("01") !== 1; - } catch (exception) {} - } - if (parseSupported) { - try { - // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal - // points. These environments, along with FF 3.1b1 and 2, - // also allow trailing commas in JSON objects and arrays. - parseSupported = parse("1.") !== 1; - } catch (exception) {} - } - } - } - } catch (exception) { - parseSupported = false; - } - } - isSupported = parseSupported; - } - } - return has[name] = !!isSupported; - } - - if (!has("json")) { - // Common `[[Class]]` name aliases. - var functionClass = "[object Function]", - dateClass = "[object Date]", - numberClass = "[object Number]", - stringClass = "[object String]", - arrayClass = "[object Array]", - booleanClass = "[object Boolean]"; - - // Detect incomplete support for accessing string characters by index. - var charIndexBuggy = has("bug-string-char-index"); - - // Define additional utility methods if the `Date` methods are buggy. - if (!isExtended) { - var floor = Math.floor; - // A mapping between the months of the year and the number of days between - // January 1st and the first of the respective month. - var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; - // Internal: Calculates the number of days between the Unix epoch and the - // first day of the given month. - var getDay = function (year, month) { - return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400); - }; - } - - // Internal: Determines if a property is a direct property of the given - // object. Delegates to the native `Object#hasOwnProperty` method. - if (!(isProperty = objectProto.hasOwnProperty)) { - isProperty = function (property) { - var members = {}, constructor; - if ((members.__proto__ = null, members.__proto__ = { - // The *proto* property cannot be set multiple times in recent - // versions of Firefox and SeaMonkey. - "toString": 1 - }, members).toString != getClass) { - // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but - // supports the mutable *proto* property. - isProperty = function (property) { - // Capture and break the object's prototype chain (see section 8.6.2 - // of the ES 5.1 spec). The parenthesized expression prevents an - // unsafe transformation by the Closure Compiler. - var original = this.__proto__, result = property in (this.__proto__ = null, this); - // Restore the original prototype chain. - this.__proto__ = original; - return result; - }; - } else { - // Capture a reference to the top-level `Object` constructor. - constructor = members.constructor; - // Use the `constructor` property to simulate `Object#hasOwnProperty` in - // other environments. - isProperty = function (property) { - var parent = (this.constructor || constructor).prototype; - return property in this && !(property in parent && this[property] === parent[property]); - }; - } - members = null; - return isProperty.call(this, property); - }; - } - - // Internal: Normalizes the `for...in` iteration algorithm across - // environments. Each enumerated key is yielded to a `callback` function. - forEach = function (object, callback) { - var size = 0, Properties, members, property; - - // Tests for bugs in the current environment's `for...in` algorithm. The - // `valueOf` property inherits the non-enumerable flag from - // `Object.prototype` in older versions of IE, Netscape, and Mozilla. - (Properties = function () { - this.valueOf = 0; - }).prototype.valueOf = 0; - - // Iterate over a new instance of the `Properties` class. - members = new Properties(); - for (property in members) { - // Ignore all properties inherited from `Object.prototype`. - if (isProperty.call(members, property)) { - size++; - } - } - Properties = members = null; - - // Normalize the iteration algorithm. - if (!size) { - // A list of non-enumerable properties inherited from `Object.prototype`. - members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"]; - // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable - // properties. - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, length; - var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty; - for (property in object) { - // Gecko <= 1.0 enumerates the `prototype` property of functions under - // certain conditions; IE does not. - if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) { - callback(property); - } - } - // Manually invoke the callback for each non-enumerable property. - for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property)); - }; - } else if (size == 2) { - // Safari <= 2.0.4 enumerates shadowed properties twice. - forEach = function (object, callback) { - // Create a set of iterated properties. - var members = {}, isFunction = getClass.call(object) == functionClass, property; - for (property in object) { - // Store each property name to prevent double enumeration. The - // `prototype` property of functions is not enumerated due to cross- - // environment inconsistencies. - if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) { - callback(property); - } - } - }; - } else { - // No bugs detected; use the standard `for...in` algorithm. - forEach = function (object, callback) { - var isFunction = getClass.call(object) == functionClass, property, isConstructor; - for (property in object) { - if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) { - callback(property); - } - } - // Manually invoke the callback for the `constructor` property due to - // cross-environment inconsistencies. - if (isConstructor || isProperty.call(object, (property = "constructor"))) { - callback(property); - } - }; - } - return forEach(object, callback); - }; - - // Public: Serializes a JavaScript `value` as a JSON string. The optional - // `filter` argument may specify either a function that alters how object and - // array members are serialized, or an array of strings and numbers that - // indicates which properties should be serialized. The optional `width` - // argument may be either a string or number that specifies the indentation - // level of the output. - if (!has("json-stringify")) { - // Internal: A map of control characters and their escaped equivalents. - var Escapes = { - 92: "\\\\", - 34: '\\"', - 8: "\\b", - 12: "\\f", - 10: "\\n", - 13: "\\r", - 9: "\\t" - }; - - // Internal: Converts `value` into a zero-padded string such that its - // length is at least equal to `width`. The `width` must be <= 6. - var leadingZeroes = "000000"; - var toPaddedString = function (width, value) { - // The `|| 0` expression is necessary to work around a bug in - // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`. - return (leadingZeroes + (value || 0)).slice(-width); - }; - - // Internal: Double-quotes a string `value`, replacing all ASCII control - // characters (characters with code unit values between 0 and 31) with - // their escaped equivalents. This is an implementation of the - // `Quote(value)` operation defined in ES 5.1 section 15.12.3. - var unicodePrefix = "\\u00"; - var quote = function (value) { - var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10; - var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value); - for (; index < length; index++) { - var charCode = value.charCodeAt(index); - // If the character is a control character, append its Unicode or - // shorthand escape sequence; otherwise, append the character as-is. - switch (charCode) { - case 8: case 9: case 10: case 12: case 13: case 34: case 92: - result += Escapes[charCode]; - break; - default: - if (charCode < 32) { - result += unicodePrefix + toPaddedString(2, charCode.toString(16)); - break; - } - result += useCharIndex ? symbols[index] : value.charAt(index); - } - } - return result + '"'; - }; - - // Internal: Recursively serializes an object. Implements the - // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations. - var serialize = function (property, object, callback, properties, whitespace, indentation, stack) { - var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result; - try { - // Necessary for host object support. - value = object[property]; - } catch (exception) {} - if (typeof value == "object" && value) { - className = getClass.call(value); - if (className == dateClass && !isProperty.call(value, "toJSON")) { - if (value > -1 / 0 && value < 1 / 0) { - // Dates are serialized according to the `Date#toJSON` method - // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15 - // for the ISO 8601 date time string format. - if (getDay) { - // Manually compute the year, month, date, hours, minutes, - // seconds, and milliseconds if the `getUTC*` methods are - // buggy. Adapted from @Yaffle's `date-shim` project. - date = floor(value / 864e5); - for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++); - for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++); - date = 1 + date - getDay(year, month); - // The `time` value specifies the time within the day (see ES - // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used - // to compute `A modulo B`, as the `%` operator does not - // correspond to the `modulo` operation for negative numbers. - time = (value % 864e5 + 864e5) % 864e5; - // The hours, minutes, seconds, and milliseconds are obtained by - // decomposing the time within the day. See section 15.9.1.10. - hours = floor(time / 36e5) % 24; - minutes = floor(time / 6e4) % 60; - seconds = floor(time / 1e3) % 60; - milliseconds = time % 1e3; - } else { - year = value.getUTCFullYear(); - month = value.getUTCMonth(); - date = value.getUTCDate(); - hours = value.getUTCHours(); - minutes = value.getUTCMinutes(); - seconds = value.getUTCSeconds(); - milliseconds = value.getUTCMilliseconds(); - } - // Serialize extended years correctly. - value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) + - "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) + - // Months, dates, hours, minutes, and seconds should have two - // digits; milliseconds should have three. - "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) + - // Milliseconds are optional in ES 5.0, but required in 5.1. - "." + toPaddedString(3, milliseconds) + "Z"; - } else { - value = null; - } - } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) { - // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the - // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3 - // ignores all `toJSON` methods on these objects unless they are - // defined directly on an instance. - value = value.toJSON(property); - } - } - if (callback) { - // If a replacement function was provided, call it to obtain the value - // for serialization. - value = callback.call(object, property, value); - } - if (value === null) { - return "null"; - } - className = getClass.call(value); - if (className == booleanClass) { - // Booleans are represented literally. - return "" + value; - } else if (className == numberClass) { - // JSON numbers must be finite. `Infinity` and `NaN` are serialized as - // `"null"`. - return value > -1 / 0 && value < 1 / 0 ? "" + value : "null"; - } else if (className == stringClass) { - // Strings are double-quoted and escaped. - return quote("" + value); - } - // Recursively serialize objects and arrays. - if (typeof value == "object") { - // Check for cyclic structures. This is a linear search; performance - // is inversely proportional to the number of unique nested objects. - for (length = stack.length; length--;) { - if (stack[length] === value) { - // Cyclic structures cannot be serialized by `JSON.stringify`. - throw TypeError(); - } - } - // Add the object to the stack of traversed objects. - stack.push(value); - results = []; - // Save the current indentation level and indent one additional level. - prefix = indentation; - indentation += whitespace; - if (className == arrayClass) { - // Recursively serialize array elements. - for (index = 0, length = value.length; index < length; index++) { - element = serialize(index, value, callback, properties, whitespace, indentation, stack); - results.push(element === undef ? "null" : element); - } - result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]"; - } else { - // Recursively serialize object members. Members are selected from - // either a user-specified list of property names, or the object - // itself. - forEach(properties || value, function (property) { - var element = serialize(property, value, callback, properties, whitespace, indentation, stack); - if (element !== undef) { - // According to ES 5.1 section 15.12.3: "If `gap` {whitespace} - // is not the empty string, let `member` {quote(property) + ":"} - // be the concatenation of `member` and the `space` character." - // The "`space` character" refers to the literal space - // character, not the `space` {width} argument provided to - // `JSON.stringify`. - results.push(quote(property) + ":" + (whitespace ? " " : "") + element); - } - }); - result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}"; - } - // Remove the object from the traversed object stack. - stack.pop(); - return result; - } - }; - - // Public: `JSON.stringify`. See ES 5.1 section 15.12.3. - exports.stringify = function (source, filter, width) { - var whitespace, callback, properties, className; - if (objectTypes[typeof filter] && filter) { - if ((className = getClass.call(filter)) == functionClass) { - callback = filter; - } else if (className == arrayClass) { - // Convert the property names array into a makeshift set. - properties = {}; - for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1)); - } - } - if (width) { - if ((className = getClass.call(width)) == numberClass) { - // Convert the `width` to an integer and create a string containing - // `width` number of space characters. - if ((width -= width % 1) > 0) { - for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " "); - } - } else if (className == stringClass) { - whitespace = width.length <= 10 ? width : width.slice(0, 10); - } - } - // Opera <= 7.54u2 discards the values associated with empty string keys - // (`""`) only if they are used directly within an object member list - // (e.g., `!("" in { "": 1})`). - return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []); - }; - } - - // Public: Parses a JSON source string. - if (!has("json-parse")) { - var fromCharCode = String.fromCharCode; - - // Internal: A map of escaped control characters and their unescaped - // equivalents. - var Unescapes = { - 92: "\\", - 34: '"', - 47: "/", - 98: "\b", - 116: "\t", - 110: "\n", - 102: "\f", - 114: "\r" - }; - - // Internal: Stores the parser state. - var Index, Source; - - // Internal: Resets the parser state and throws a `SyntaxError`. - var abort = function () { - Index = Source = null; - throw SyntaxError(); - }; - - // Internal: Returns the next token, or `"$"` if the parser has reached - // the end of the source string. A token may be a string, number, `null` - // literal, or Boolean literal. - var lex = function () { - var source = Source, length = source.length, value, begin, position, isSigned, charCode; - while (Index < length) { - charCode = source.charCodeAt(Index); - switch (charCode) { - case 9: case 10: case 13: case 32: - // Skip whitespace tokens, including tabs, carriage returns, line - // feeds, and space characters. - Index++; - break; - case 123: case 125: case 91: case 93: case 58: case 44: - // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at - // the current position. - value = charIndexBuggy ? source.charAt(Index) : source[Index]; - Index++; - return value; - case 34: - // `"` delimits a JSON string; advance to the next character and - // begin parsing the string. String tokens are prefixed with the - // sentinel `@` character to distinguish them from punctuators and - // end-of-string tokens. - for (value = "@", Index++; Index < length;) { - charCode = source.charCodeAt(Index); - if (charCode < 32) { - // Unescaped ASCII control characters (those with a code unit - // less than the space character) are not permitted. - abort(); - } else if (charCode == 92) { - // A reverse solidus (`\`) marks the beginning of an escaped - // control character (including `"`, `\`, and `/`) or Unicode - // escape sequence. - charCode = source.charCodeAt(++Index); - switch (charCode) { - case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114: - // Revive escaped control characters. - value += Unescapes[charCode]; - Index++; - break; - case 117: - // `\u` marks the beginning of a Unicode escape sequence. - // Advance to the first character and validate the - // four-digit code point. - begin = ++Index; - for (position = Index + 4; Index < position; Index++) { - charCode = source.charCodeAt(Index); - // A valid sequence comprises four hexdigits (case- - // insensitive) that form a single hexadecimal value. - if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) { - // Invalid Unicode escape sequence. - abort(); - } - } - // Revive the escaped character. - value += fromCharCode("0x" + source.slice(begin, Index)); - break; - default: - // Invalid escape sequence. - abort(); - } - } else { - if (charCode == 34) { - // An unescaped double-quote character marks the end of the - // string. - break; - } - charCode = source.charCodeAt(Index); - begin = Index; - // Optimize for the common case where a string is valid. - while (charCode >= 32 && charCode != 92 && charCode != 34) { - charCode = source.charCodeAt(++Index); - } - // Append the string as-is. - value += source.slice(begin, Index); - } - } - if (source.charCodeAt(Index) == 34) { - // Advance to the next character and return the revived string. - Index++; - return value; - } - // Unterminated string. - abort(); - default: - // Parse numbers and literals. - begin = Index; - // Advance past the negative sign, if one is specified. - if (charCode == 45) { - isSigned = true; - charCode = source.charCodeAt(++Index); - } - // Parse an integer or floating-point value. - if (charCode >= 48 && charCode <= 57) { - // Leading zeroes are interpreted as octal literals. - if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) { - // Illegal octal literal. - abort(); - } - isSigned = false; - // Parse the integer component. - for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++); - // Floats cannot contain a leading decimal point; however, this - // case is already accounted for by the parser. - if (source.charCodeAt(Index) == 46) { - position = ++Index; - // Parse the decimal component. - for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - // Illegal trailing decimal. - abort(); - } - Index = position; - } - // Parse exponents. The `e` denoting the exponent is - // case-insensitive. - charCode = source.charCodeAt(Index); - if (charCode == 101 || charCode == 69) { - charCode = source.charCodeAt(++Index); - // Skip past the sign following the exponent, if one is - // specified. - if (charCode == 43 || charCode == 45) { - Index++; - } - // Parse the exponential component. - for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++); - if (position == Index) { - // Illegal empty exponent. - abort(); - } - Index = position; - } - // Coerce the parsed value to a JavaScript number. - return +source.slice(begin, Index); - } - // A negative sign may only precede numbers. - if (isSigned) { - abort(); - } - // `true`, `false`, and `null` literals. - if (source.slice(Index, Index + 4) == "true") { - Index += 4; - return true; - } else if (source.slice(Index, Index + 5) == "false") { - Index += 5; - return false; - } else if (source.slice(Index, Index + 4) == "null") { - Index += 4; - return null; - } - // Unrecognized token. - abort(); - } - } - // Return the sentinel `$` character if the parser has reached the end - // of the source string. - return "$"; - }; - - // Internal: Parses a JSON `value` token. - var get = function (value) { - var results, hasMembers; - if (value == "$") { - // Unexpected end of input. - abort(); - } - if (typeof value == "string") { - if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") { - // Remove the sentinel `@` character. - return value.slice(1); - } - // Parse object and array literals. - if (value == "[") { - // Parses a JSON array, returning a new JavaScript array. - results = []; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - // A closing square bracket marks the end of the array literal. - if (value == "]") { - break; - } - // If the array literal contains elements, the current token - // should be a comma separating the previous element from the - // next. - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "]") { - // Unexpected trailing `,` in array literal. - abort(); - } - } else { - // A `,` must separate each array element. - abort(); - } - } - // Elisions and leading commas are not permitted. - if (value == ",") { - abort(); - } - results.push(get(value)); - } - return results; - } else if (value == "{") { - // Parses a JSON object, returning a new JavaScript object. - results = {}; - for (;; hasMembers || (hasMembers = true)) { - value = lex(); - // A closing curly brace marks the end of the object literal. - if (value == "}") { - break; - } - // If the object literal contains members, the current token - // should be a comma separator. - if (hasMembers) { - if (value == ",") { - value = lex(); - if (value == "}") { - // Unexpected trailing `,` in object literal. - abort(); - } - } else { - // A `,` must separate each object member. - abort(); - } - } - // Leading commas are not permitted, object property names must be - // double-quoted strings, and a `:` must separate each property - // name and value. - if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") { - abort(); - } - results[value.slice(1)] = get(lex()); - } - return results; - } - // Unexpected token encountered. - abort(); - } - return value; - }; - - // Internal: Updates a traversed object member. - var update = function (source, property, callback) { - var element = walk(source, property, callback); - if (element === undef) { - delete source[property]; - } else { - source[property] = element; - } - }; - - // Internal: Recursively traverses a parsed JSON object, invoking the - // `callback` function for each value. This is an implementation of the - // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2. - var walk = function (source, property, callback) { - var value = source[property], length; - if (typeof value == "object" && value) { - // `forEach` can't be used to traverse an array in Opera <= 8.54 - // because its `Object#hasOwnProperty` implementation returns `false` - // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`). - if (getClass.call(value) == arrayClass) { - for (length = value.length; length--;) { - update(value, length, callback); - } - } else { - forEach(value, function (property) { - update(value, property, callback); - }); - } - } - return callback.call(source, property, value); - }; - - // Public: `JSON.parse`. See ES 5.1 section 15.12.2. - exports.parse = function (source, callback) { - var result, value; - Index = 0; - Source = "" + source; - result = get(lex()); - // If a JSON string contains multiple tokens, it is invalid. - if (lex() != "$") { - abort(); - } - // Reset the parser state. - Index = Source = null; - return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result; - }; - } - } - - exports["runInContext"] = runInContext; - return exports; - } - - if (freeExports && !isLoader) { - // Export for CommonJS environments. - runInContext(root, freeExports); - } else { - // Export for web browsers and JavaScript engines. - var nativeJSON = root.JSON, - previousJSON = root["JSON3"], - isRestored = false; - - var JSON3 = runInContext(root, (root["JSON3"] = { - // Public: Restores the original value of the global `JSON` object and - // returns a reference to the `JSON3` object. - "noConflict": function () { - if (!isRestored) { - isRestored = true; - root.JSON = nativeJSON; - root["JSON3"] = previousJSON; - nativeJSON = previousJSON = null; - } - return JSON3; - } - })); - - root.JSON = { - "parse": JSON3.parse, - "stringify": JSON3.stringify - }; - } - - // Export for asynchronous module loaders. - if (isLoader) { - define(function () { - return JSON3; - }); - } -}).call(this); - -//############################################################################## -// DomUtils.js -//############################################################################## - -(function () { - - /** - * A few utilities for interacting with the dom. - * @class DomUtils - */ - var s = {}; - - s.appendToHead = function (el) { - s.getHead().appendChild(el) - } - - s.getHead = function () { - return document.head || document.getElementsByTagName("head")[0]; - } - - s.getBody = function () { - return document.body || document.getElementsByTagName("body")[0]; - } - - createjs.DomUtils = s; - -}()); - -//############################################################################## -// DataUtils.js -//############################################################################## - -(function () { - - /** - * A few data utilities for formatting different data types. - * @class DataUtils - */ - var s = {}; - - // static methods - /** - * Parse XML using the DOM. This is required when preloading XML or SVG. - * @method parseXML - * @param {String} text The raw text or XML that is loaded by XHR. - * @param {String} type The mime type of the XML. Use "text/xml" for XML, and "image/svg+xml" for SVG parsing. - * @return {XML} An XML document - * @static - */ - s.parseXML = function (text, type) { - var xml = null; - // CocoonJS does not support XML parsing with either method. - - // Most browsers will use DOMParser - // IE fails on certain SVG files, so we have a fallback below. - try { - if (window.DOMParser) { - var parser = new DOMParser(); - xml = parser.parseFromString(text, type); - } - } catch (e) { - } - - // Fallback for IE support. - if (!xml) { - try { - xml = new ActiveXObject("Microsoft.XMLDOM"); - xml.async = false; - xml.loadXML(text); - } catch (e) { - xml = null; - } - } - - return xml; - }; - - /** - * Parse a string into an Object. - * @method parseJSON - * @param {String} value The loaded JSON string - * @returns {Object} A JavaScript object. - */ - s.parseJSON = function (value) { - if (value == null) { - return null; - } - - try { - return JSON.parse(value); - } catch (e) { - // TODO; Handle this with a custom error? - throw e; - } - }; - - createjs.DataUtils = s; - -}()); - -//############################################################################## -// LoadItem.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, - * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A - * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the - * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} - * @class LoadItem - * @constructor - * @since 0.6.0 - */ - function LoadItem() { - /** - * The source of the file that is being loaded. This property is required. The source can either be a - * string (recommended), or an HTML tag. - * This can also be an object, but in that case it has to include a type and be handled by a plugin. - * @property src - * @type {String} - * @default null - */ - this.src = null; - - /** - * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also - * be set manually. This is helpful in cases where a file does not have an extension. - * @property type - * @type {String} - * @default null - */ - this.type = null; - - /** - * A string identifier which can be used to reference the loaded object. If none is provided, this will be - * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. - * @property id - * @type {String} - * @default null - */ - this.id = null; - - /** - * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest - * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has - * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this - * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in - * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. - * @property maintainOrder - * @type {Boolean} - * @default false - */ - this.maintainOrder = false; - - /** - * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. - * @property callback - * @type {String} - * @default null - */ - this.callback = null; - - /** - * An arbitrary data object, which is included with the loaded object. - * @property data - * @type {Object} - * @default null - */ - this.data = null; - - /** - * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or - * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as - * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @property method - * @type {String} - * @default get - */ - this.method = createjs.LoadItem.GET; - - /** - * An object hash of name/value pairs to send to the server. - * @property values - * @type {Object} - * @default null - */ - this.values = null; - - /** - * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default - * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the - * default headers by including them in your headers object. - * @property headers - * @type {Object} - * @default null - */ - this.headers = null; - - /** - * Enable credentials for XHR requests. - * @property withCredentials - * @type {Boolean} - * @default false - */ - this.withCredentials = false; - - /** - * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text - * based files (json, xml, text, css, js). - * @property mimeType - * @type {String} - * @default null - */ - this.mimeType = null; - - /** - * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. - * @property crossOrigin - * @type {boolean} - * @default Anonymous - */ - this.crossOrigin = null; - - /** - * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property loadTimeout - * @type {Number} - * @default 8000 (8 seconds) - */ - this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - }; - - var p = LoadItem.prototype = {}; - var s = LoadItem; - - /** - * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property LOAD_TIMEOUT_DEFAULT - * @type {number} - * @static - */ - s.LOAD_TIMEOUT_DEFAULT = 8000; - - /** - * Create a LoadItem. - *
      - *
    • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
    • - *
    • LoadItem instances are returned as-is
    • - *
    • Objects are returned with any needed properties added
    • - *
    - * @method create - * @param {LoadItem|String|Object} value The load item value - * @returns {LoadItem|Object} - * @static - */ - s.create = function (value) { - if (typeof value == "string") { - var item = new LoadItem(); - item.src = value; - return item; - } else if (value instanceof s) { - return value; - } else if (value instanceof Object && value.src) { - if (value.loadTimeout == null) { - value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - } - return value; - } else { - throw new Error("Type not recognized."); - } - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

    Example

    - * - * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the LoadItem instance. - * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - createjs.LoadItem = s; - -}()); - -//############################################################################## -// RequestUtils.js -//############################################################################## - -(function () { - - /** - * Utilities that assist with parsing load items, and determining file types, etc. - * @class RequestUtils - */ - var s = {}; - - /** - * The Regular Expression used to test file URLS for an absolute path. - * @property ABSOLUTE_PATH - * @type {RegExp} - * @static - */ - s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; - - /** - * The Regular Expression used to test file URLS for a relative path. - * @property RELATIVE_PATH - * @type {RegExp} - * @static - */ - s.RELATIVE_PATT = (/^[./]*?\//i); - - /** - * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string - * removed. - * @property EXTENSION_PATT - * @type {RegExp} - * @static - */ - s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; - - /** - * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: - *
      - *
    • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or - * `//networkPath`)
    • - *
    • If the path is relative. Relative paths start with `../` or `/path` (or similar)
    • - *
    • The file extension. This is determined by the filename with an extension. Query strings are dropped, and - * the file path is expected to follow the format `name.ext`.
    • - *
    - * @method parseURI - * @param {String} path - * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` - * property, which is the lowercase extension. - * @static - */ - s.parseURI = function (path) { - var info = {absolute: false, relative: false}; - if (path == null) { return info; } - - // Drop the query string - var queryIndex = path.indexOf("?"); - if (queryIndex > -1) { - path = path.substr(0, queryIndex); - } - - // Absolute - var match; - if (s.ABSOLUTE_PATT.test(path)) { - info.absolute = true; - - // Relative - } else if (s.RELATIVE_PATT.test(path)) { - info.relative = true; - } - - // Extension - if (match = path.match(s.EXTENSION_PATT)) { - info.extension = match[1].toLowerCase(); - } - return info; - }; - - /** - * Formats an object into a query string for either a POST or GET request. - * @method formatQueryString - * @param {Object} data The data to convert to a query string. - * @param {Array} [query] Existing name/value pairs to append on to this query. - * @static - */ - s.formatQueryString = function (data, query) { - if (data == null) { - throw new Error('You must specify data.'); - } - var params = []; - for (var n in data) { - params.push(n + '=' + escape(data[n])); - } - if (query) { - params = params.concat(query); - } - return params.join('&'); - }; - - /** - * A utility method that builds a file path using a source and a data object, and formats it into a new path. - * @method buildPath - * @param {String} src The source path to add values to. - * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the - * path will be preserved. - * @returns {string} A formatted string that contains the path and the supplied parameters. - * @static - */ - s.buildPath = function (src, data) { - if (data == null) { - return src; - } - - var query = []; - var idx = src.indexOf('?'); - - if (idx != -1) { - var q = src.slice(idx + 1); - query = query.concat(q.split('&')); - } - - if (idx != -1) { - return src.slice(0, idx) + '?' + this.formatQueryString(data, query); - } else { - return src + '?' + this.formatQueryString(data, query); - } - }; - - /** - * @method isCrossDomain - * @param {LoadItem|Object} item A load item with a `src` property. - * @return {Boolean} If the load item is loading from a different domain than the current location. - * @static - */ - s.isCrossDomain = function (item) { - var target = document.createElement("a"); - target.href = item.src; - - var host = document.createElement("a"); - host.href = location.href; - - var crossdomain = (target.hostname != "") && - (target.port != host.port || - target.protocol != host.protocol || - target.hostname != host.hostname); - return crossdomain; - }; - - /** - * @method isLocal - * @param {LoadItem|Object} item A load item with a `src` property - * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as - * well. - * @static - */ - s.isLocal = function (item) { - var target = document.createElement("a"); - target.href = item.src; - return target.hostname == "" && target.protocol == "file:"; - }; - - /** - * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked - * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play - * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get - * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on - * {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @method isBinary - * @param {String} type The item type. - * @return {Boolean} If the specified type is binary. - * @static - */ - s.isBinary = function (type) { - switch (type) { - case createjs.AbstractLoader.IMAGE: - case createjs.AbstractLoader.BINARY: - return true; - default: - return false; - } - }; - - /** - * Check if item is a valid HTMLImageElement - * @method isImageTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isImageTag = function(item) { - return item instanceof HTMLImageElement; - }; - - /** - * Check if item is a valid HTMLAudioElement - * @method isAudioTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isAudioTag = function(item) { - if (window.HTMLAudioElement) { - return item instanceof HTMLAudioElement; - } else { - return false; - } - }; - - /** - * Check if item is a valid HTMLVideoElement - * @method isVideoTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isVideoTag = function(item) { - if (window.HTMLVideoElement) { - return item instanceof HTMLVideoElement; - } else { - return false; - } - }; - - /** - * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. - * @method isText - * @param {String} type The item type. - * @return {Boolean} If the specified type is text. - * @static - */ - s.isText = function (type) { - switch (type) { - case createjs.AbstractLoader.TEXT: - case createjs.AbstractLoader.JSON: - case createjs.AbstractLoader.MANIFEST: - case createjs.AbstractLoader.XML: - case createjs.AbstractLoader.CSS: - case createjs.AbstractLoader.SVG: - case createjs.AbstractLoader.JAVASCRIPT: - case createjs.AbstractLoader.SPRITESHEET: - return true; - default: - return false; - } - }; - - /** - * Determine the type of the object using common extensions. Note that the type can be passed in with the load item - * if it is an unusual extension. - * @method getTypeByExtension - * @param {String} extension The file extension to use to determine the load type. - * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if - * the type can not be determined by the extension. - * @static - */ - s.getTypeByExtension = function (extension) { - if (extension == null) { - return createjs.AbstractLoader.TEXT; - } - - switch (extension.toLowerCase()) { - case "jpeg": - case "jpg": - case "gif": - case "png": - case "webp": - case "bmp": - return createjs.AbstractLoader.IMAGE; - case "ogg": - case "mp3": - case "webm": - return createjs.AbstractLoader.SOUND; - case "mp4": - case "webm": - case "ts": - return createjs.AbstractLoader.VIDEO; - case "json": - return createjs.AbstractLoader.JSON; - case "xml": - return createjs.AbstractLoader.XML; - case "css": - return createjs.AbstractLoader.CSS; - case "js": - return createjs.AbstractLoader.JAVASCRIPT; - case 'svg': - return createjs.AbstractLoader.SVG; - default: - return createjs.AbstractLoader.TEXT; - } - }; - - createjs.RequestUtils = s; - -}()); - -//############################################################################## -// AbstractLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - -// constructor - /** - * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, - * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. - * @class AbstractLoader - * @param {LoadItem|object|string} loadItem The item to be loaded. - * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a - * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the - * other, so this is a suggested directive. - * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, - * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. - * @extends EventDispatcher - */ - function AbstractLoader(loadItem, preferXHR, type) { - this.EventDispatcher_constructor(); - - // public properties - /** - * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches - * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. - * @property loaded - * @type {Boolean} - * @default false - */ - this.loaded = false; - - /** - * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property - * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} - * instead. - * @property canceled - * @type {Boolean} - * @default false - * @readonly - */ - this.canceled = false; - - /** - * The current load progress (percentage) for this item. This will be a number between 0 and 1. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.loadFile("largeImage.png"); - * queue.on("progress", function() { - * console.log("Progress:", queue.progress, event.progress); - * }); - * - * @property progress - * @type {Number} - * @default 0 - */ - this.progress = 0; - - /** - * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of - * supported types. - * @property type - * @type {String} - */ - this.type = type; - - /** - * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader - * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property - * can be overridden to provide custom formatting. - * - * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be - * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks - * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is - * called in the current scope, as well as the success and error callbacks. - * - *

    Example asynchronous resultFormatter

    - * - * function _formatResult(loader) { - * return function(success, error) { - * if (errorCondition) { error(errorDetailEvent); } - * success(result); - * } - * } - * @property resultFormatter - * @type {Function} - * @default null - */ - this.resultFormatter = null; - - // protected properties - /** - * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. - * @property _item - * @type {LoadItem|Object} - * @private - */ - if (loadItem) { - this._item = createjs.LoadItem.create(loadItem); - } else { - this._item = null; - } - - /** - * Whether the loader will try and load content using XHR (true) or HTML tags (false). - * @property _preferXHR - * @type {Boolean} - * @private - */ - this._preferXHR = preferXHR; - - /** - * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For - * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. - * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. - * @property _result - * @type {Object|String} - * @private - */ - this._result = null; - - /** - * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} - * method, and passing `true`. - * @property _rawResult - * @type {Object|String} - * @private - */ - this._rawResult = null; - - /** - * A list of items that loaders load behind the scenes. This does not include the main item the loader is - * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _loadItems - * @type {null} - * @protected - */ - this._loadedItems = null; - - /** - * The attribute the items loaded using tags use for the source. - * @type {string} - * @default null - * @private - */ - this._tagSrcAttribute = null; - - /** - * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. - * @property _tag - * @type {Object} - * @private - */ - this._tag = null; - }; - - var p = createjs.extend(AbstractLoader, createjs.EventDispatcher); - var s = AbstractLoader; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - - /** - * Defines a POST request, use for a method value when loading data. - * @property POST - * @type {string} - * @default post - * @static - */ - s.POST = "POST"; - - /** - * Defines a GET request, use for a method value when loading data. - * @property GET - * @type {string} - * @default get - * @static - */ - s.GET = "GET"; - - /** - * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. - * @property BINARY - * @type {String} - * @default binary - * @static - * @since 0.6.0 - */ - s.BINARY = "binary"; - - /** - * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a - * <style> tag when loaded with tags. - * @property CSS - * @type {String} - * @default css - * @static - * @since 0.6.0 - */ - s.CSS = "css"; - - /** - * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. - * @property IMAGE - * @type {String} - * @default image - * @static - * @since 0.6.0 - */ - s.IMAGE = "image"; - - /** - * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a - * <script> tag. - * - * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into - * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, - * only tag-loaded scripts are injected. - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @since 0.6.0 - */ - s.JAVASCRIPT = "javascript"; - - /** - * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, - * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON - * must contain a matching wrapper function. - * @property JSON - * @type {String} - * @default json - * @static - * @since 0.6.0 - */ - s.JSON = "json"; - - /** - * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. - * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} - * property is set to. - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @since 0.6.0 - */ - s.JSONP = "jsonp"; - - /** - * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded - * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an - * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, - * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.6.0 - */ - s.MANIFEST = "manifest"; - - /** - * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an - * <audio> tag. - * @property SOUND - * @type {String} - * @default sound - * @static - * @since 0.6.0 - */ - s.SOUND = "sound"; - - /** - * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an - * <video> tag. - * @property VIDEO - * @type {String} - * @default video - * @static - * @since 0.6.0 - */ - s.VIDEO = "video"; - - /** - * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. - * @property SPRITESHEET - * @type {String} - * @default spritesheet - * @static - * @since 0.6.0 - */ - s.SPRITESHEET = "spritesheet"; - - /** - * The preload type for SVG files. - * @property SVG - * @type {String} - * @default svg - * @static - * @since 0.6.0 - */ - s.SVG = "svg"; - - /** - * The preload type for text files, which is also the default file type if the type can not be determined. Text is - * loaded as raw text. - * @property TEXT - * @type {String} - * @default text - * @static - * @since 0.6.0 - */ - s.TEXT = "text"; - - /** - * The preload type for xml files. XML is loaded into an XML document. - * @property XML - * @type {String} - * @default xml - * @static - * @since 0.6.0 - */ - s.XML = "xml"; - -// Events - /** - * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to - * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event progress - * @since 0.3.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. - * @event loadstart - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.1 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.0 - */ - - /** - * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was - * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was - * just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event error - * @since 0.3.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. - * This enables loaders to maintain internal queues, and surface file load errors. - * @event fileerror - * @param {Object} target The object that dispatched the event. - * @param {String} type The even type ("fileerror") - * @param {LoadItem|object} The item that encountered the error - * @since 0.6.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables - * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s - * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a - * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("fileload") - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.6.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. - * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. - * @event initialize - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("initialize") - * @param {AbstractLoader} loader The loader that has been initialized. - */ - - - /** - * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was - * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will - * be a {{#crossLink "LoadItem"}}{{/crossLink}}. - * @method getItem - * @return {Object} The manifest item that this loader is responsible for loading. - * @since 0.6.0 - */ - p.getItem = function () { - return this._item; - }; - - /** - * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} - * event is dispatched. - * @method getResult - * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded - * data (if it exists). - * @return {Object} - * @since 0.6.0 - */ - p.getResult = function (raw) { - return raw ? this._rawResult : this._result; - }; - - /** - * Return the `tag` this object creates or uses for loading. - * @method getTag - * @return {Object} The tag instance - * @since 0.6.0 - */ - p.getTag = function () { - return this._tag; - }; - - /** - * Set the `tag` this item uses for loading. - * @method setTag - * @param {Object} tag The tag instance - * @since 0.6.0 - */ - p.setTag = function(tag) { - this._tag = tag; - }; - - /** - * Begin loading the item. This method is required when using a loader by itself. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.on("complete", handleComplete); - * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet - * queue.load(); - * - * @method load - */ - p.load = function () { - this._createRequest(); - - this._request.on("complete", this, this); - this._request.on("progress", this, this); - this._request.on("loadStart", this, this); - this._request.on("abort", this, this); - this._request.on("timeout", this, this); - this._request.on("error", this, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._request; - this.dispatchEvent(evt); - - this._request.load(); - }; - - /** - * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in - * the background), but events will not longer be dispatched. - * @method cancel - */ - p.cancel = function () { - this.canceled = true; - this.destroy(); - }; - - /** - * Clean up the loader. - * @method destroy - */ - p.destroy = function() { - if (this._request) { - this._request.removeAllEventListeners(); - this._request.destroy(); - } - - this._request = null; - - this._item = null; - this._rawResult = null; - this._result = null; - - this._loadItems = null; - - this.removeAllEventListeners(); - }; - - /** - * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to expose items it loads internally. - * @method getLoadedItems - * @return {Array} A list of the items loaded by the loader. - * @since 0.6.0 - */ - p.getLoadedItems = function () { - return this._loadedItems; - }; - - - // Private methods - /** - * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or - * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. - * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, - * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. - * @method _createRequest - * @protected - */ - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); - } else { - this._request = new createjs.XHRRequest(this._item); - } - }; - - /** - * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented - * by loaders that require tag loading. - * @method _createTag - * @param {String} src The tag source - * @return {HTMLElement} The tag that was created - * @protected - */ - p._createTag = function(src) { return null; }; - - /** - * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendLoadStart - * @protected - */ - p._sendLoadStart = function () { - if (this._isCanceled()) { return; } - this.dispatchEvent("loadstart"); - }; - - /** - * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. - * @method _sendProgress - * @param {Number | Object} value The progress of the loaded item, or an object containing loaded - * and total properties. - * @protected - */ - p._sendProgress = function (value) { - if (this._isCanceled()) { return; } - var event = null; - if (typeof(value) == "number") { - this.progress = value; - event = new createjs.ProgressEvent(this.progress); - } else { - event = value; - this.progress = value.loaded / value.total; - event.progress = this.progress; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - } - this.hasEventListener("progress") && this.dispatchEvent(event); - }; - - /** - * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event - * @method _sendComplete - * @protected - */ - p._sendComplete = function () { - if (this._isCanceled()) { return; } - - this.loaded = true; - - var event = new createjs.Event("complete"); - event.rawResult = this._rawResult; - - if (this._result != null) { - event.result = this._result; - } - - this.dispatchEvent(event); - }; - - /** - * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendError - * @param {ErrorEvent} event The event object containing specific error properties. - * @protected - */ - p._sendError = function (event) { - if (this._isCanceled() || !this.hasEventListener("error")) { return; } - if (event == null) { - event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error - } - this.dispatchEvent(event); - }; - - /** - * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events - * do not cause issues after the queue has been cleaned up. - * @method _isCanceled - * @return {Boolean} If the loader has been canceled. - * @protected - */ - p._isCanceled = function () { - if (window.createjs == null || this.canceled) { - return true; - } - return false; - }; - - /** - * A custom result formatter function, which is called just before a request dispatches its complete event. Most - * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The - * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. - * @property resultFormatter - * @type Function - * @return {Object} The formatted result - * @since 0.6.0 - */ - p.resultFormatter = null; - - /** - * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but - * this method can be overridden for custom behaviours. - * @method handleEvent - * @param {Event} event The event that the internal request dispatches. - * @protected - * @since 0.6.0 - */ - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target._response; - var result = this.resultFormatter && this.resultFormatter(this); - if (result instanceof Function) { - result.call(this, - createjs.proxy(this._resultFormatSuccess, this), - createjs.proxy(this._resultFormatFailed, this) - ); - } else { - this._result = result || this._rawResult; - this._sendComplete(); - } - break; - case "progress": - this._sendProgress(event); - break; - case "error": - this._sendError(event); - break; - case "loadstart": - this._sendLoadStart(); - break; - case "abort": - case "timeout": - if (!this._isCanceled()) { - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); - } - break; - } - }; - - /** - * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} result The formatted result - * @private - */ - p._resultFormatSuccess = function (result) { - this._result = result; - this._sendComplete(); - }; - - /** - * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} error The error event - * @private - */ - p._resultFormatFailed = function (event) { - this._sendError(event); - }; - - /** - * @method buildPath - * @protected - * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} - * instead. - */ - p.buildPath = function (src, data) { - return createjs.RequestUtils.buildPath(src, data); - }; - - /** - * @method toString - * @return {String} a string representation of the instance. - */ - p.toString = function () { - return "[PreloadJS AbstractLoader]"; - }; - - createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher"); - -}()); - -//############################################################################## -// AbstractMediaLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that - * handle HTML media elements, such as Video and Audio. - * @class AbstractMediaLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @param {String} type The type of media to load. Usually "video" or "audio". - * @extends AbstractLoader - * @constructor - */ - function AbstractMediaLoader(loadItem, preferXHR, type) { - this.AbstractLoader_constructor(loadItem, preferXHR, type); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader); - - // static properties - // public methods - p.load = function () { - // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here. - if (!this._tag) { - this._tag = this._createTag(this._item.src); - } - - this._tag.preload = "auto"; - this._tag.load(); - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Creates a new tag for loading if it doesn't exist yet. - * @method _createTag - * @private - */ - p._createTag = function () {}; - - - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); - } else { - this._request = new createjs.XHRRequest(this._item); - } - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for media files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLVideoElement|HTMLAudioElement} - * @private - */ - p._formatResult = function (loader) { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.onstalled = null; - if (this._preferXHR) { - var URL = window.URL || window.webkitURL; - var result = loader.getResult(true); - - loader.getTag().src = URL.createObjectURL(result); - } - return loader.getTag(); - }; - - createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// AbstractRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, - * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the - * hood to get data. - * @class AbstractRequest - * @param {LoadItem} item - * @constructor - */ - var AbstractRequest = function (item) { - this._item = item; - }; - - var p = createjs.extend(AbstractRequest, createjs.EventDispatcher); - - // public methods - /** - * Begin a load. - * @method load - */ - p.load = function() {}; - - /** - * Clean up a request. - * @method destroy - */ - p.destroy = function() {}; - - /** - * Cancel an in-progress request. - * @method cancel - */ - p.cancel = function() {}; - - createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher"); - -}()); - -//############################################################################## -// TagRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. - * @class TagRequest - * @param {LoadItem} loadItem - * @param {HTMLElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - */ - function TagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - /** - * The HTML tag instance that is used to load. - * @property _tag - * @type {HTMLElement} - * @protected - */ - this._tag = tag; - - /** - * The tag attribute that specifies the source, such as "src", "href", etc. - * @property _tagSrcAttribute - * @type {String} - * @protected - */ - this._tagSrcAttribute = srcAttribute; - - /** - * A method closure used for handling the tag load event. - * @property _loadedHandler - * @type {Function} - * @private - */ - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - - /** - * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. - * @property _addedToDOM - * @type {Boolean} - * @private - */ - this._addedToDOM = false; - - /** - * Determines what the tags initial style.visibility was, so we can set it correctly after a load. - * - * @type {null} - * @private - */ - this._startTagVisibility = null; - }; - - var p = createjs.extend(TagRequest, createjs.AbstractRequest); - - // public methods - p.load = function () { - this._tag.onload = createjs.proxy(this._handleTagComplete, this); - this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this); - this._tag.onerror = createjs.proxy(this._handleError, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._tag; - - this.dispatchEvent(evt); - - this._hideTag(); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - this._tag[this._tagSrcAttribute] = this._item.src; - - // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. - if (this._tag.parentNode == null) { - window.document.body.appendChild(this._tag); - this._addedToDOM = true; - } - }; - - p.destroy = function() { - this._clean(); - this._tag = null; - - this.AbstractRequest_destroy(); - }; - - // private methods - /** - * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT - * and LINK tags), but other cases may exist. - * @method _handleReadyStateChange - * @private - */ - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - /** - * Handle any error events from the tag. - * @method _handleError - * @protected - */ - p._handleError = function() { - this._clean(); - this.dispatchEvent("error"); - }; - - /** - * Handle the tag's onload callback. - * @method _handleTagComplete - * @private - */ - p._handleTagComplete = function () { - this._rawResult = this._tag; - this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; - - this._clean(); - this._showTag(); - - this.dispatchEvent("complete"); - }; - - /** - * The tag request has not loaded within the time specified in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleTimeout = function () { - this._clean(); - this.dispatchEvent(new createjs.Event("timeout")); - }; - - /** - * Remove event listeners, but don't destroy the request object - * @method _clean - * @private - */ - p._clean = function() { - this._tag.onload = null; - this._tag.onreadystatechange = null; - this._tag.onerror = null; - if (this._addedToDOM && this._tag.parentNode != null) { - this._tag.parentNode.removeChild(this._tag); - } - clearTimeout(this._loadTimeout); - }; - - p._hideTag = function() { - this._startTagVisibility = this._tag.style.visibility; - this._tag.style.visibility = "hidden"; - }; - - p._showTag = function() { - this._tag.style.visibility = this._startTagVisibility; - }; - - /** - * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio - * that is already in a load, but not complete. - * @method _handleStalled - * @private - */ - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// MediaTagRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio. - * @class MediaTagRequest - * @param {LoadItem} loadItem - * @param {HTMLAudioElement|HTMLVideoElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - * @constructor - */ - function MediaTagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - this._tag = tag; - this._tagSrcAttribute = srcAttribute; - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - }; - - var p = createjs.extend(MediaTagRequest, createjs.TagRequest); - var s = MediaTagRequest; - - // public methods - p.load = function () { - var sc = createjs.proxy(this._handleStalled, this); - this._stalledCallback = sc; - - var pc = createjs.proxy(this._handleProgress, this); - this._handleProgress = pc; - - this._tag.addEventListener("stalled", sc); - this._tag.addEventListener("progress", pc); - - // This will tell us when audio is buffered enough to play through, but not when its loaded. - // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient. - this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event. - - this.TagRequest_load(); - }; - - // private methods - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - /** - * An XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - // protected methods - p._clean = function () { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.removeEventListener("stalled", this._stalledCallback); - this._tag.removeEventListener("progress", this._progressCallback); - - this.TagRequest__clean(); - }; - - createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest"); - -}()); - -//############################################################################## -// XHRRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - -// constructor - /** - * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used - * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. - * XHR requests load the content as text or binary data, provide progress and consistent completion events, and - * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for - * cross-domain loading. - * @class XHRRequest - * @constructor - * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * for an overview of supported file properties. - * @extends AbstractLoader - */ - function XHRRequest (item) { - this.AbstractRequest_constructor(item); - - // protected properties - /** - * A reference to the XHR request used to load the content. - * @property _request - * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} - * @private - */ - this._request = null; - - /** - * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, - * typically IE9). - * @property _loadTimeout - * @type {Number} - * @private - */ - this._loadTimeout = null; - - /** - * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect - * the version, so we use capabilities to make a best guess. - * @property _xhrLevel - * @type {Number} - * @default 1 - * @private - */ - this._xhrLevel = 1; - - /** - * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be - * null until the file is loaded. - * @property _response - * @type {mixed} - * @private - */ - this._response = null; - - /** - * The response of the loaded file before it is modified. In most cases, content is converted from raw text to - * an HTML tag or a formatted object which is set to the result property, but the developer may still - * want to access the raw content as it was loaded. - * @property _rawResponse - * @type {String|Object} - * @private - */ - this._rawResponse = null; - - this._canceled = false; - - // Setup our event handlers now. - this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this); - this._handleProgressProxy = createjs.proxy(this._handleProgress, this); - this._handleAbortProxy = createjs.proxy(this._handleAbort, this); - this._handleErrorProxy = createjs.proxy(this._handleError, this); - this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this); - this._handleLoadProxy = createjs.proxy(this._handleLoad, this); - this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this); - - if (!this._createXHR(item)) { - //TODO: Throw error? - } - }; - - var p = createjs.extend(XHRRequest, createjs.AbstractRequest); - -// static properties - /** - * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. - * @property ACTIVEX_VERSIONS - * @type {Array} - * @since 0.4.2 - * @private - */ - XHRRequest.ACTIVEX_VERSIONS = [ - "Msxml2.XMLHTTP.6.0", - "Msxml2.XMLHTTP.5.0", - "Msxml2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", - "MSXML2.XMLHTTP", - "Microsoft.XMLHTTP" - ]; - -// Public methods - /** - * Look up the loaded result. - * @method getResult - * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
      - *
    • An image tag (<image />) for images
    • - *
    • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the - * HTML head.
    • - *
    • A style tag for CSS (<style />)
    • - *
    • Raw text for TEXT
    • - *
    • A formatted JavaScript object defined by JSON
    • - *
    • An XML document
    • - *
    • An binary arraybuffer loaded by XHR
    • - *
    - * Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (raw) { - if (raw && this._rawResponse) { - return this._rawResponse; - } - return this._response; - }; - - // Overrides abstract method in AbstractRequest - p.cancel = function () { - this.canceled = true; - this._clean(); - this._request.abort(); - }; - - // Overrides abstract method in AbstractLoader - p.load = function () { - if (this._request == null) { - this._handleError(); - return; - } - - //Events - if (this._request.addEventListener != null) { - this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); - this._request.addEventListener("progress", this._handleProgressProxy, false); - this._request.addEventListener("abort", this._handleAbortProxy, false); - this._request.addEventListener("error", this._handleErrorProxy, false); - this._request.addEventListener("timeout", this._handleTimeoutProxy, false); - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.addEventListener("load", this._handleLoadProxy, false); - this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); - } else { - // IE9 support - this._request.onloadstart = this._handleLoadStartProxy; - this._request.onprogress = this._handleProgressProxy; - this._request.onabort = this._handleAbortProxy; - this._request.onerror = this._handleErrorProxy; - this._request.ontimeout = this._handleTimeoutProxy; - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.onload = this._handleLoadProxy; - this._request.onreadystatechange = this._handleReadyStateChangeProxy; - } - - // Set up a timeout if we don't have XHR2 - if (this._xhrLevel == 1) { - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - } - - // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome - try { - if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) { - this._request.send(); - } else if (this._item.method == createjs.AbstractLoader.POST) { - this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)); - } - } catch (error) { - this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error)); - } - }; - - p.setResponseType = function (type) { - // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded - if (type === 'blob') { - type = window.URL ? 'blob' : 'arraybuffer'; - this._responseType = type; - } - this._request.responseType = type; - }; - - /** - * Get all the response headers from the XmlHttpRequest. - * - * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match - * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, - * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE - * pair. - * @method getAllResponseHeaders - * @return {String} - * @since 0.4.1 - */ - p.getAllResponseHeaders = function () { - if (this._request.getAllResponseHeaders instanceof Function) { - return this._request.getAllResponseHeaders(); - } else { - return null; - } - }; - - /** - * Get a specific response header from the XmlHttpRequest. - * - * From the docs: Returns the header field value from the response of which the field name matches - * header, unless the field name is Set-Cookie or Set-Cookie2. - * @method getResponseHeader - * @param {String} header The header name to retrieve. - * @return {String} - * @since 0.4.1 - */ - p.getResponseHeader = function (header) { - if (this._request.getResponseHeader instanceof Function) { - return this._request.getResponseHeader(header); - } else { - return null; - } - }; - -// protected methods - /** - * The XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - /** - * The XHR request has reported a load start. - * @method _handleLoadStart - * @param {Object} event The XHR loadStart event. - * @private - */ - p._handleLoadStart = function (event) { - clearTimeout(this._loadTimeout); - this.dispatchEvent("loadstart"); - }; - - /** - * The XHR request has reported an abort event. - * @method handleAbort - * @param {Object} event The XHR abort event. - * @private - */ - p._handleAbort = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event)); - }; - - /** - * The XHR request has reported an error event. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleError = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent(event.message)); - }; - - /** - * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload - * event, so we must monitor the readyStateChange to determine if the file is loaded. - * @method _handleReadyStateChange - * @param {Object} event The XHR readyStateChange event. - * @private - */ - p._handleReadyStateChange = function (event) { - if (this._request.readyState == 4) { - this._handleLoad(); - } - }; - - /** - * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has - * request.readyState == 4. Only the first call to this method will be processed. - * @method _handleLoad - * @param {Object} event The XHR load event. - * @private - */ - p._handleLoad = function (event) { - if (this.loaded) { - return; - } - this.loaded = true; - - var error = this._checkError(); - if (error) { - this._handleError(error); - return; - } - - this._response = this._getResponse(); - // Convert arraybuffer back to blob - if (this._responseType === 'arraybuffer') { - try { - this._response = new Blob([this._response]); - } catch (e) { - // Fallback to use BlobBuilder if Blob constructor is not supported - // Tested on Android 2.3 ~ 4.2 and iOS5 safari - window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - if (e.name === 'TypeError' && window.BlobBuilder) { - var builder = new BlobBuilder(); - builder.append(this._response); - this._response = builder.getBlob(); - } - } - } - this._clean(); - - this.dispatchEvent(new createjs.Event("complete")); - }; - - /** - * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout - * callback. - * @method _handleTimeout - * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. - * @private - */ - p._handleTimeout = function (event) { - this._clean(); - - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event)); - }; - -// Protected - /** - * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note - * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. - * @method _checkError - * @return {int} If the request status returns an error code. - * @private - */ - p._checkError = function () { - //LM: Probably need additional handlers here, maybe 501 - var status = parseInt(this._request.status); - - switch (status) { - case 404: // Not Found - case 0: // Not Loaded - return new Error(status); - } - return null; - }; - - /** - * Validate the response. Different browsers have different approaches, some of which throw errors when accessed - * in other browsers. If there is no response, the _response property will remain null. - * @method _getResponse - * @private - */ - p._getResponse = function () { - if (this._response != null) { - return this._response; - } - - if (this._request.response != null) { - return this._request.response; - } - - // Android 2.2 uses .responseText - try { - if (this._request.responseText != null) { - return this._request.responseText; - } - } catch (e) { - } - - // When loading XML, IE9 does not return .response, instead it returns responseXML.xml - try { - if (this._request.responseXML != null) { - return this._request.responseXML; - } - } catch (e) { - } - - return null; - }; - - /** - * Create an XHR request. Depending on a number of factors, we get totally different results. - *
    1. Some browsers get an XDomainRequest when loading cross-domain.
    2. - *
    3. XMLHttpRequest are created when available.
    4. - *
    5. ActiveX.XMLHTTP objects are used in older IE browsers.
    6. - *
    7. Text requests override the mime type if possible
    8. - *
    9. Origin headers are sent for crossdomain requests in some browsers.
    10. - *
    11. Binary loads set the response type to "arraybuffer"
    - * @method _createXHR - * @param {Object} item The requested item that is being loaded. - * @return {Boolean} If an XHR request or equivalent was successfully created. - * @private - */ - p._createXHR = function (item) { - // Check for cross-domain loads. We can't fully support them, but we can try. - var crossdomain = createjs.RequestUtils.isCrossDomain(item); - var headers = {}; - - // Create the request. Fallback to whatever support we have. - var req = null; - if (window.XMLHttpRequest) { - req = new XMLHttpRequest(); - // This is 8 or 9, so use XDomainRequest instead. - if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { - req = new XDomainRequest(); - } - } else { // Old IE versions use a different approach - for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { - var axVersion = s.ACTIVEX_VERSIONS[i]; - try { - req = new ActiveXObject(axVersion); - break; - } catch (e) { - } - } - if (req == null) { - return false; - } - } - - // Default to utf-8 for Text requests. - if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) { - item.mimeType = "text/plain; charset=utf-8"; - } - - // IE9 doesn't support overrideMimeType(), so we need to check for it. - if (item.mimeType && req.overrideMimeType) { - req.overrideMimeType(item.mimeType); - } - - // Determine the XHR level - this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; - - var src = null; - if (item.method == createjs.AbstractLoader.GET) { - src = createjs.RequestUtils.buildPath(item.src, item.values); - } else { - src = item.src; - } - - // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) - req.open(item.method || createjs.AbstractLoader.GET, src, true); - - if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { - headers["Origin"] = location.origin; - } - - // To send data we need to set the Content-type header) - if (item.values && item.method == createjs.AbstractLoader.POST) { - headers["Content-Type"] = "application/x-www-form-urlencoded"; - } - - if (!crossdomain && !headers["X-Requested-With"]) { - headers["X-Requested-With"] = "XMLHttpRequest"; - } - - if (item.headers) { - for (var n in item.headers) { - headers[n] = item.headers[n]; - } - } - - for (n in headers) { - req.setRequestHeader(n, headers[n]) - } - - if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { - req.withCredentials = item.withCredentials; - } - - this._request = req; - - return true; - }; - - /** - * A request has completed (or failed or canceled), and needs to be disposed. - * @method _clean - * @private - */ - p._clean = function () { - clearTimeout(this._loadTimeout); - - if (this._request.removeEventListener != null) { - this._request.removeEventListener("loadstart", this._handleLoadStartProxy); - this._request.removeEventListener("progress", this._handleProgressProxy); - this._request.removeEventListener("abort", this._handleAbortProxy); - this._request.removeEventListener("error", this._handleErrorProxy); - this._request.removeEventListener("timeout", this._handleTimeoutProxy); - this._request.removeEventListener("load", this._handleLoadProxy); - this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); - } else { - this._request.onloadstart = null; - this._request.onprogress = null; - this._request.onabort = null; - this._request.onerror = null; - this._request.ontimeout = null; - this._request.onload = null; - this._request.onreadystatechange = null; - } - }; - - p.toString = function () { - return "[PreloadJS XHRRequest]"; - }; - - createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// LoadQueue.js -//############################################################################## - -this.createjs = this.createjs || {}; - -/* - TODO: WINDOWS ISSUES - * No error for HTML audio in IE 678 - * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR - * No script complete handler in IE 67 TAGS (XHR is fine) - * No XML/JSON in IE6 TAGS - * Need to hide loading SVG in Opera TAGS - * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking) - * SVG no load or failure in Opera XHR - * Reported issues with IE7/8 - */ - -(function () { - "use strict"; - -// constructor - /** - * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either - * a single file, or queue of files. - * - * Creating a Queue
    - * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR - * argument to false. - * - * var queue = new createjs.LoadQueue(true); - * - * Listening for Events
    - * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}} - * lets you add as many listeners as you want for events. You can subscribe to the following events:
      - *
    • {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all - * files
    • - *
    • {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with - * any file.
    • - *
    • {{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has - * changed.
    • - *
    • {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
    • - *
    • {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note - * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
    • - *
    - * - * queue.on("fileload", handleFileLoad, this); - * queue.on("complete", handleComplete, this); - * - * Adding files and manifests
    - * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a - * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are - * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you - * like. - * - * queue.loadFile("filePath/file.jpg"); - * queue.loadFile({id:"image", src:"filePath/file.jpg"}); - * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]); - * - * // Use an external manifest - * queue.loadManifest("path/to/manifest.json"); - * queue.loadManifest({src:"manifest.json", type:"manifest"}); - * - * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not - * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin - * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a - * `loadNow` argument of `true`. - * - * queue.load(); - * - * File Types
    - * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS - * should handle the majority of standard file and url formats, and works with common file extensions. If you have - * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a - * type property with any manifest item. - * - * queue.loadFile({src:"path/to/myFile.mp3x", type:createjs.AbstractLoader.SOUND}); - * - * // Note that PreloadJS will not read a file extension from the query string - * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:createjs.AbstractLoader.IMAGE}); - * - * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include: - *
      - *
    • {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
    • - *
    • {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}: CSS files
    • - *
    • {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}: Common image formats
    • - *
    • {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}: JavaScript files
    • - *
    • {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}: JSON data
    • - *
    • {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}: JSON files cross-domain
    • - *
    • {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see - * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
    • - *
    • {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}: Audio file formats
    • - *
    • {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This - * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
    • - *
    • {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}: SVG files
    • - *
    • {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
    • - *
    • {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
    • - *
    • {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
    • - *
    - * - * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better - * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but - * are deprecated. - * - * Handling Results
    - * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is - * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a - * formatted object that can be used immediately, including: - *
      - *
    • Binary: The binary loaded result
    • - *
    • CSS: A <link /> tag
    • - *
    • Image: An <img /> tag
    • - *
    • JavaScript: A <script /> tag
    • - *
    • JSON/JSONP: A formatted JavaScript Object
    • - *
    • Manifest: A JavaScript object. - *
    • Sound: An <audio /> tag - *
    • SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images. - *
    • SVG: An <object /> tag
    • - *
    • Text: Raw text
    • - *
    • Video: A Video DOM node
    • - *
    • XML: An XML DOM node
    • - *
    - * - * function handleFileLoad(event) { - * var item = event.item; // A reference to the item that was passed in to the LoadQueue - * var type = item.type; - * - * // Add any images to the page body. - * if (type == createjs.LoadQueue.IMAGE) { - * document.body.appendChild(event.result); - * } - * } - * - * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up - * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the - * "src" or file path can be used instead, including the `path` defined by a manifest, but not including - * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content. - * - * var image = queue.getResult("image"); - * document.body.appendChild(image); - * - * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd - * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript, - * CSS, XML, SVG, and JSON objects, or anything loaded with XHR. - * - * var image = queue.getResult("image", true); // load the binary image data loaded with XHR. - * - * Plugins
    - * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio, - * make sure to install the SoundJS Sound class, which will help load HTML audio, - * Flash audio, and WebAudio files. This should be installed before loading any audio files. - * - * queue.installPlugin(createjs.Sound); - * - *

    Known Browser Issues

    - *
      - *
    • Browsers without audio support can not load audio files.
    • - *
    • Safari on Mac OS X can only play HTML audio if QuickTime is installed
    • - *
    • HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other - * than Chrome will continue to download in the background.
    • - *
    • When loading scripts using tags, they are automatically added to the document.
    • - *
    • Scripts loaded via XHR may not be properly inspectable with browser tools.
    • - *
    • IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require - * XHR to work.
    • - *
    • Content loaded via tags will not show progress, and will continue to download in the background when - * canceled, although no events will be dispatched.
    • - *
    - * - * @class LoadQueue - * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP - * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR - * when necessary. - * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue - * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../` - * will not receive a base path. - * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To - * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any - * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin - * parameter is deprecated. Use LoadItem.crossOrigin instead - * - * @constructor - * @extends AbstractLoader - */ - function LoadQueue (preferXHR, basePath, crossOrigin) { - this.AbstractLoader_constructor(); - - /** - * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}. - * @property _plugins - * @type {Array} - * @private - * @since 0.6.1 - */ - this._plugins = []; - - /** - * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _typeCallbacks - * @type {Object} - * @private - */ - this._typeCallbacks = {}; - - /** - * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the - * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}} - * method for more information. - * @property _extensionCallbacks - * @type {null} - * @private - */ - this._extensionCallbacks = {}; - - /** - * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and - * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed. - * @property next - * @type {LoadQueue} - * @default null - */ - this.next = null; - - /** - * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head - * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas - * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order - * specified. - * - * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}} - * property on the load item, or by ensuring that only one connection can be open at a time using - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property - * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the - * `maintainScriptOrder` to `false` during a load will not change items already in a queue. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(3); // Set a higher number to load multiple items at once - * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order - * queue.loadManifest([ - * "script1.js", - * "script2.js", - * "image.png", // Load any time - * {src: "image2.png", maintainOrder: true} // Will wait for script2.js - * "image3.png", - * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR) - * ]); - * - * @property maintainScriptOrder - * @type {Boolean} - * @default true - */ - this.maintainScriptOrder = true; - - /** - * Determines if the LoadQueue will stop processing the current queue when an error is encountered. - * @property stopOnError - * @type {Boolean} - * @default false - */ - this.stopOnError = false; - - /** - * The number of maximum open connections that a loadQueue tries to maintain. Please see - * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information. - * @property _maxConnections - * @type {Number} - * @default 1 - * @private - */ - this._maxConnections = 1; - - /** - * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the - * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can - * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is - * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the - * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of - * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. - * - * Loaders can be removed from PreloadJS by simply not including them. - * - * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list - * so that they are checked first. - * @property _availableLoaders - * @type {Array} - * @private - * @since 0.6.0 - */ - this._availableLoaders = [ - createjs.ImageLoader, - createjs.JavaScriptLoader, - createjs.CSSLoader, - createjs.JSONLoader, - createjs.JSONPLoader, - createjs.SoundLoader, - createjs.ManifestLoader, - createjs.SpriteSheetLoader, - createjs.XMLLoader, - createjs.SVGLoader, - createjs.BinaryLoader, - createjs.VideoLoader, - createjs.TextLoader - ]; - - /** - * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}. - * @property _defaultLoaderLength - * @type {Number} - * @private - * @since 0.6.0 - */ - this._defaultLoaderLength = this._availableLoaders.length; - - this.init(preferXHR, basePath, crossOrigin); - } - - var p = createjs.extend(LoadQueue, createjs.AbstractLoader); - var s = LoadQueue; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - /** - * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue. - * @method init - * @param preferXHR - * @param basePath - * @param crossOrigin - * @private - */ - p.init = function (preferXHR, basePath, crossOrigin) { - - // public properties - /** - * @property useXHR - * @type {Boolean} - * @readonly - * @default true - * @deprecated Use preferXHR instead. - */ - this.useXHR = true; - - /** - * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR - * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR, - * and plain text can not be loaded with tags, so it will default the the correct type instead of using the - * user-defined type. - * @type {Boolean} - * @default true - * @since 0.6.0 - */ - this.preferXHR = true; //TODO: Get/Set - this._preferXHR = true; - this.setPreferXHR(preferXHR); - - // protected properties - /** - * Whether the queue is currently paused or not. - * @property _paused - * @type {boolean} - * @private - */ - this._paused = false; - - /** - * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The - * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such - * as `http://`, or a relative path such as `../`. - * @property _basePath - * @type {String} - * @private - * @since 0.3.1 - */ - this._basePath = basePath; - - /** - * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded - * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by - * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues, - * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are "" - * and "Anonymous". - * @property _crossOrigin - * @type {String} - * @default "" - * @private - * @since 0.4.1 - */ - this._crossOrigin = crossOrigin; - - /** - * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first - * file is requested. - * @property _loadStartWasDispatched - * @type {Boolean} - * @default false - * @private - */ - this._loadStartWasDispatched = false; - - /** - * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when - * using a script tag to do preloading. - * @property _currentlyLoadingScript - * @type {Boolean} - * @private - */ - this._currentlyLoadingScript = null; - - /** - * An array containing the currently downloading files. - * @property _currentLoads - * @type {Array} - * @private - */ - this._currentLoads = []; - - /** - * An array containing the queued items that have not yet started downloading. - * @property _loadQueue - * @type {Array} - * @private - */ - this._loadQueue = []; - - /** - * An array containing downloads that have not completed, so that the LoadQueue can be properly reset. - * @property _loadQueueBackup - * @type {Array} - * @private - */ - this._loadQueueBackup = []; - - /** - * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}} - * id. - * @property _loadItemsById - * @type {Object} - * @private - */ - this._loadItemsById = {}; - - /** - * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}} - * source. - * @property _loadItemsBySrc - * @type {Object} - * @private - */ - this._loadItemsBySrc = {}; - - /** - * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedResults - * @type {Object} - * @private - */ - this._loadedResults = {}; - - /** - * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}. - * @property _loadedRawResults - * @type {Object} - * @private - */ - this._loadedRawResults = {}; - - /** - * The number of items that have been requested. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. This does not include items inside of loaders such as the - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _numItems - * @type {Number} - * @default 0 - * @private - */ - this._numItems = 0; - - /** - * The number of items that have completed loaded. This helps manage an overall progress without knowing how large - * the files are before they are downloaded. - * @property _numItemsLoaded - * @type {Number} - * @default 0 - * @private - */ - this._numItemsLoaded = 0; - - /** - * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right - * order. - * @property _scriptOrder - * @type {Array} - * @private - */ - this._scriptOrder = []; - - /** - * A list of scripts that have been loaded. Items are added to this list as null when they are - * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true - * once they are complete and have been dispatched. - * @property _loadedScripts - * @type {Array} - * @private - */ - this._loadedScripts = []; - - /** - * The last progress amount. This is used to suppress duplicate progress events. - * @property _lastProgress - * @type {Number} - * @private - * @since 0.6.0 - */ - this._lastProgress = NaN; - - }; - -// static properties - /** - * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event is dispatched if the timeout is reached before any data is received. - * @property loadTimeout - * @type {Number} - * @default 8000 - * @static - * @since 0.4.1 - * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property. - */ - s.loadTimeout = 8000; - - /** - * The time in milliseconds to assume a load has failed. - * @property LOAD_TIMEOUT - * @type {Number} - * @default 0 - * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property. - */ - s.LOAD_TIMEOUT = 0; - -// Preload Types - /** - * @property BINARY - * @type {String} - * @default binary - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead. - */ - s.BINARY = createjs.AbstractLoader.BINARY; - - /** - * @property CSS - * @type {String} - * @default css - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. - */ - s.CSS = createjs.AbstractLoader.CSS; - - /** - * @property IMAGE - * @type {String} - * @default image - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead. - */ - s.IMAGE = createjs.AbstractLoader.IMAGE; - - /** - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.JAVASCRIPT = createjs.AbstractLoader.JAVASCRIPT; - - /** - * @property JSON - * @type {String} - * @default json - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead. - */ - s.JSON = createjs.AbstractLoader.JSON; - - /** - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead. - */ - s.JSONP = createjs.AbstractLoader.JSONP; - - /** - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.4.1 - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead. - */ - s.MANIFEST = createjs.AbstractLoader.MANIFEST; - - /** - * @property SOUND - * @type {String} - * @default sound - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.SOUND = createjs.AbstractLoader.SOUND; - - /** - * @property VIDEO - * @type {String} - * @default video - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead. - */ - s.VIDEO = createjs.AbstractLoader.VIDEO; - - /** - * @property SVG - * @type {String} - * @default svg - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead. - */ - s.SVG = createjs.AbstractLoader.SVG; - - /** - * @property TEXT - * @type {String} - * @default text - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead. - */ - s.TEXT = createjs.AbstractLoader.TEXT; - - /** - * @property XML - * @type {String} - * @default xml - * @static - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead. - */ - s.XML = createjs.AbstractLoader.XML; - - /** - * @property POST - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead. - */ - s.POST = createjs.AbstractLoader.POST; - - /** - * @property GET - * @type {string} - * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead. - */ - s.GET = createjs.AbstractLoader.GET; - -// events - /** - * This event is fired when an individual file has loaded, and been processed. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.3.0 - */ - - /** - * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes. - * @event fileprogress - * @since 0.3.0 - */ - - /** - * This event is fired when an individual file starts to load. - * @event filestart - * @param {Object} The object that dispatched the event. - * @param {String} type The event type. - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a property. - */ - - /** - * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from - * a LoadQueue instance. - * @event initialize - * @private - */ - -// public methods - /** - * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders. - * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added - * once, and will be prepended to the list of available loaders. - * @method registerLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to add. - * @since 0.6.0 - */ - p.registerLoader = function (loader) { - if (!loader || !loader.canLoadItem) { - throw new Error("loader is of an incorrect type."); - } else if (this._availableLoaders.indexOf(loader) != -1) { - throw new Error("loader already exists."); //LM: Maybe just silently fail here - } - - this._availableLoaders.unshift(loader); - }; - - /** - * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be - * unregistered, the default loaders will always be available. - * @method unregisterLoader - * @param {Function|AbstractLoader} loader The AbstractLoader class to remove - */ - p.unregisterLoader = function (loader) { - var idx = this._availableLoaders.indexOf(loader); - if (idx != -1 && idx < this._defaultLoaderLength - 1) { - this._availableLoaders.splice(idx, 1); - } - }; - - /** - * @method setUseXHR - * @param {Boolean} value The new useXHR value to set. - * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if - * the provided value argument was true. - * @since 0.3.0 - * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the - * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead. - */ - p.setUseXHR = function (value) { - return this.setPreferXHR(value); - }; - - /** - * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may - * fail, or be ignored depending on the browser's capabilities and the load type. - * @method setPreferXHR - * @param {Boolean} value - * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set. - * @since 0.6.0 - */ - p.setPreferXHR = function (value) { - // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it. - //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR. - this.preferXHR = (value != false && window.XMLHttpRequest != null); - return this.preferXHR; - }; - - /** - * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded - * content, and allows the queue to be used again. - * @method removeAll - * @since 0.3.0 - */ - p.removeAll = function () { - this.remove(); - }; - - /** - * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed. - * This also removes internal references to loaded item(s). - * - *

    Example

    - * - * queue.loadManifest([ - * {src:"test.png", id:"png"}, - * {src:"test.jpg", id:"jpg"}, - * {src:"test.mp3", id:"mp3"} - * ]); - * queue.remove("png"); // Single item by ID - * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src. - * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src. - * - * @method remove - * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of - * items, or multiple items as arguments. - * @since 0.3.0 - */ - p.remove = function (idsOrUrls) { - var args = null; - - if (idsOrUrls && !Array.isArray(idsOrUrls)) { - args = [idsOrUrls]; - } else if (idsOrUrls) { - args = idsOrUrls; - } else if (arguments.length > 0) { - return; - } - - var itemsWereRemoved = false; - - // Destroy everything - if (!args) { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } - this.init(this.preferXHR, this._basePath); - - // Remove specific items - } else { - while (args.length) { - var item = args.pop(); - var r = this.getResult(item); - - //Remove from the main load Queue - for (i = this._loadQueue.length - 1; i >= 0; i--) { - loadItem = this._loadQueue[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueue.splice(i, 1)[0].cancel(); - break; - } - } - - //Remove from the backup queue - for (i = this._loadQueueBackup.length - 1; i >= 0; i--) { - loadItem = this._loadQueueBackup[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._loadQueueBackup.splice(i, 1)[0].cancel(); - break; - } - } - - if (r) { - this._disposeItem(this.getItem(item)); - } else { - for (var i = this._currentLoads.length - 1; i >= 0; i--) { - var loadItem = this._currentLoads[i].getItem(); - if (loadItem.id == item || loadItem.src == item) { - this._currentLoads.splice(i, 1)[0].cancel(); - itemsWereRemoved = true; - break; - } - } - } - } - - // If this was called during a load, try to load the next item. - if (itemsWereRemoved) { - this._loadNext(); - } - } - }; - - /** - * Stops all open loads, destroys any loaded items, and resets the queue, so all items can - * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the - * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method. - * @method reset - * @since 0.3.0 - */ - p.reset = function () { - this.close(); - for (var n in this._loadItemsById) { - this._disposeItem(this._loadItemsById[n]); - } - - //Reset the queue to its start state - var a = []; - for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) { - a.push(this._loadQueueBackup[i].getItem()); - } - - this.loadManifest(a, false); - }; - - /** - * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc). - * Currently, only one plugin can exist per type/extension. - * - * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information - * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the - * {{#crossLink "SamplePlugin"}}{{/crossLink}} class. - * - * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned - * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its - * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when - * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these - * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}} - * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}. - * - * @method installPlugin - * @param {Function} plugin The plugin class to install. - */ - p.installPlugin = function (plugin) { - if (plugin == null) { - return; - } - - if (plugin.getPreloadHandlers != null) { - this._plugins.push(plugin); - var map = plugin.getPreloadHandlers(); - map.scope = plugin; - - if (map.types != null) { - for (var i = 0, l = map.types.length; i < l; i++) { - this._typeCallbacks[map.types[i]] = map; - } - } - - if (map.extensions != null) { - for (i = 0, l = map.extensions.length; i < l; i++) { - this._extensionCallbacks[map.extensions[i]] = map; - } - } - } - }; - - /** - * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum - * number of open connections, so any additional connections may remain in a pending state until the browser - * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} - * is `true`, only one script is loaded at a time due to browser limitations. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.setMaxConnections(10); // Allow 10 concurrent loads - * - * @method setMaxConnections - * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue - * is open at any time. - */ - p.setMaxConnections = function (value) { - this._maxConnections = value; - if (!this._paused && this._loadQueue.length > 0) { - this._loadNext(); - } - }; - - /** - * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadFile - * @param {LoadItem|Object|String} file The file object or path to load. A file can be either - *
      - *
    • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
    • - *
    • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
    • - *
    • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
    • - *
    - * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadFile = function (file, loadNow, basePath) { - if (file == null) { - var event = new createjs.ErrorEvent("PRELOAD_NO_FILE"); - this._sendError(event); - return; - } - this._addItem(file, null, basePath); - - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } - }; - - /** - * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method. - * The files in the manifest are requested in the same order, but may complete in a different order if the max - * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load - * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is - * default). - * - * Files are always appended to the current queue, so this method can be used multiple times to add files. - * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method. - * @method loadManifest - * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of - * manifests: - *
      - *
    1. A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, - * which defines the list of files to load, and can optionally contain a "path" property, which will be - * prepended to each file in the list.
    2. - *
    3. An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP - * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, - * and can optionally contain a "path" property, which will be prepended to each file in the list.
    4. - *
    5. An object which contains a "manifest" property, which defines the list of files to load, and can - * optionally contain a "path" property, which will be prepended to each file in the list.
    6. - *
    7. An Array of files to load.
    8. - *
    - * - * Each "file" in a manifest can be either: - *
      - *
    • A {{#crossLink "LoadItem"}}{{/crossLink}} instance
    • - *
    • An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
    • - *
    • OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}} - * in the background.
    • - *
    - * - * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default - * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is - * `true`, the queue will resume automatically. - * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the - * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}}, - * its files will NOT use the basePath parameter. The basePath parameter is deprecated. - * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue - * constructor, or a `path` property in a manifest definition. - */ - p.loadManifest = function (manifest, loadNow, basePath) { - var fileList = null; - var path = null; - - // Array-based list of items - if (Array.isArray(manifest)) { - if (manifest.length == 0) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY"); - this._sendError(event); - return; - } - fileList = manifest; - - // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded. - } else if (typeof(manifest) === "string") { - fileList = [ - { - src: manifest, - type: s.MANIFEST - } - ]; - - } else if (typeof(manifest) == "object") { - - // An object that defines a manifest path - if (manifest.src !== undefined) { - if (manifest.type == null) { - manifest.type = s.MANIFEST; - } else if (manifest.type != s.MANIFEST) { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE"); - this._sendError(event); - } - fileList = [manifest]; - - // An object that defines a manifest - } else if (manifest.manifest !== undefined) { - fileList = manifest.manifest; - path = manifest.path; - } - - // Unsupported. This will throw an error. - } else { - var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL"); - this._sendError(event); - return; - } - - for (var i = 0, l = fileList.length; i < l; i++) { - this._addItem(fileList[i], path, basePath); - } - - if (loadNow !== false) { - this.setPaused(false); - } else { - this.setPaused(true); - } - - }; - - /** - * Start a LoadQueue that was created, but not automatically started. - * @method load - */ - p.load = function () { - this.setPaused(false); - }; - - /** - * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was - * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getItem - * @param {String} value The id or src of the load item. - * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} - * event as the `item` parameter. - */ - p.getItem = function (value) { - return this._loadItemsById[value] || this._loadItemsBySrc[value]; - }; - - /** - * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id" - * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The - * `basePath` will not be part of the ID. - * @method getResult - * @param {String} value The id or src of the load item. - * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
      - *
    • An image tag (<image />) for images
    • - *
    • A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML - * DOM.
    • - *
    • A style tag for CSS (<style /> or <link >)
    • - *
    • Raw text for TEXT
    • - *
    • A formatted JavaScript object defined by JSON
    • - *
    • An XML document
    • - *
    • A binary arraybuffer loaded by XHR
    • - *
    • An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play - * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method - * which can not be used to play audio back.
    • - *
    - * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item` - * parameter. Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (value, rawResult) { - var item = this._loadItemsById[value] || this._loadItemsBySrc[value]; - if (item == null) { - return null; - } - var id = item.id; - if (rawResult && this._loadedRawResults[id]) { - return this._loadedRawResults[id]; - } - return this._loadedResults[id]; - }; - - /** - * Generate an list of items loaded by this queue. - * @method getItems - * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress - * and failed load items will also be included. - * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}}, - * result, and rawResult. - * @since 0.6.0 - */ - p.getItems = function (loaded) { - var arr = []; - for (var n in this._loadItemsById) { - var item = this._loadItemsById[n]; - var result = this.getResult(n); - if (loaded === true && result == null) { - continue; - } - arr.push({ - item: item, - result: result, - rawResult: this.getResult(n, true) - }); - } - return arr; - }; - - /** - * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not - * be processed when active loads complete. LoadQueues are not paused by default. - * - * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow` - * argument is `false`. - * @method setPaused - * @param {Boolean} value Whether the queue should be paused or not. - */ - p.setPaused = function (value) { - this._paused = value; - if (!this._paused) { - this._loadNext(); - } - }; - - /** - * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from - * starting to download. Note that currently any active loads will remain open, and events may be processed. - * - * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead. - * @method close - */ - p.close = function () { - while (this._currentLoads.length) { - this._currentLoads.pop().cancel(); - } - this._scriptOrder.length = 0; - this._loadedScripts.length = 0; - this.loadStartWasDispatched = false; - this._itemCount = 0; - this._lastProgress = NaN; - }; - -// protected methods - /** - * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to - * load the content. The load queue is populated with the loader instance that handles preloading, and not the load - * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}} - * method. - * @method _addItem - * @param {String|Object} value The item to add to the queue. - * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is - * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was - * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after. - * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged - * version. - * @private - */ - p._addItem = function (value, path, basePath) { - var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src. - if (item == null) { - return; - } // Sometimes plugins or types should be skipped. - var loader = this._createLoader(item); - if (loader != null) { - if ("plugins" in loader) { - loader.plugins = this._plugins; - } - item._loader = loader; - this._loadQueue.push(loader); - this._loadQueueBackup.push(loader); - - this._numItems++; - this._updateProgress(); - - // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time. - if ((this.maintainScriptOrder - && item.type == createjs.LoadQueue.JAVASCRIPT - //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way - ) - || item.maintainOrder === true) { - this._scriptOrder.push(item); - this._loadedScripts.push(null); - } - } - }; - - /** - * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of - * item is determined by browser support, requirements based on the file type, and developer settings. For example, - * XHR is only used for file types that support it in new browsers. - * - * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may - * alter the load item. - * @method _createLoadItem - * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded. - * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will - * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}} - * when it is added. - * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to - * the path argument. - * @return {Object} The loader instance that will be used. - * @private - */ - p._createLoadItem = function (value, path, basePath) { - var item = createjs.LoadItem.create(value); - if (item == null) { - return null; - } - - var bp = ""; // Store the generated basePath - var useBasePath = basePath || this._basePath; - - if (item.src instanceof Object) { - if (!item.type) { - return null; - } // the the src is an object, type is required to pass off to plugin - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; - } - } else if (useBasePath != null) { - bp = useBasePath; - } - } else { - // Determine Extension, etc. - var match = createjs.RequestUtils.parseURI(item.src); - if (match.extension) { - item.ext = match.extension; - } - if (item.type == null) { - item.type = createjs.RequestUtils.getTypeByExtension(item.ext); - } - - // Inject path & basePath - var autoId = item.src; - if (!match.absolute && !match.relative) { - if (path) { - bp = path; - var pathMatch = createjs.RequestUtils.parseURI(path); - autoId = path + autoId; - // Also append basePath - if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) { - bp = useBasePath + bp; - } - } else if (useBasePath != null) { - bp = useBasePath; - } - } - item.src = bp + item.src; - } - item.path = bp; - - // If there's no id, set one now. - if (item.id === undefined || item.id === null || item.id === "") { - item.id = autoId; - } - - // Give plugins a chance to modify the loadItem: - var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext]; - if (customHandler) { - // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately) - var result = customHandler.callback.call(customHandler.scope, item, this); - - // The plugin will handle the load, or has canceled it. Ignore it. - if (result === false) { - return null; - - // Load as normal: - } else if (result === true) { - // Do Nothing - - // Result is a loader class: - } else if (result != null) { - item._loader = result; - } - - // Update the extension in case the type changed: - match = createjs.RequestUtils.parseURI(item.src); - if (match.extension != null) { - item.ext = match.extension; - } - } - - // Store the item for lookup. This also helps clean-up later. - this._loadItemsById[item.id] = item; - this._loadItemsBySrc[item.src] = item; - - if (item.crossOrigin == null) { - item.crossOrigin = this._crossOrigin; - } - - return item; - }; - - /** - * Create a loader for a load item. - * @method _createLoader - * @param {Object} item A formatted load item that can be used to generate a loader. - * @return {AbstractLoader} A loader that can be used to load content. - * @private - */ - p._createLoader = function (item) { - if (item._loader != null) { // A plugin already specified a loader - return item._loader; - } - - // Initially, try and use the provided/supported XHR mode: - var preferXHR = this.preferXHR; - - for (var i = 0; i < this._availableLoaders.length; i++) { - var loader = this._availableLoaders[i]; - if (loader && loader.canLoadItem(item)) { - return new loader(item, preferXHR); - } - } - - // TODO: Log error (requires createjs.log) - return null; - }; - - /** - * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event - * is processed. The queue will "fill up" any empty slots, up to the max connection specified using - * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded - * using tags, which have to be loaded one at a time to maintain load order. - * @method _loadNext - * @private - */ - p._loadNext = function () { - if (this._paused) { - return; - } - - // Only dispatch loadstart event when the first file is loaded. - if (!this._loadStartWasDispatched) { - this._sendLoadStart(); - this._loadStartWasDispatched = true; - } - - // The queue has completed. - if (this._numItems == this._numItemsLoaded) { - this.loaded = true; - this._sendComplete(); - - // Load the next queue, if it has been defined. - if (this.next && this.next.load) { - this.next.load(); - } - } else { - this.loaded = false; - } - - // Must iterate forwards to load in the right order. - for (var i = 0; i < this._loadQueue.length; i++) { - if (this._currentLoads.length >= this._maxConnections) { - break; - } - var loader = this._loadQueue[i]; - - // Determine if we should be only loading one tag-script at a time: - // Note: maintainOrder items don't do anything here because we can hold onto their loaded value - if (!this._canStartLoad(loader)) { - continue; - } - this._loadQueue.splice(i, 1); - i--; - this._loadItem(loader); - } - }; - - /** - * Begin loading an item. Event listeners are not added to the loaders until the load starts. - * @method _loadItem - * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader. - * @private - */ - p._loadItem = function (loader) { - loader.on("fileload", this._handleFileLoad, this); - loader.on("progress", this._handleProgress, this); - loader.on("complete", this._handleFileComplete, this); - loader.on("error", this._handleError, this); - loader.on("fileerror", this._handleFileError, this); - this._currentLoads.push(loader); - this._sendFileStart(loader.getItem()); - loader.load(); - }; - - /** - * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}} - * events. - * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader. - * @private - * @since 0.6.0 - */ - p._handleFileLoad = function (event) { - event.target = null; - this.dispatchEvent(event); - }; - - /** - * The callback that is fired when a loader encounters an error from an internal file load operation. This enables - * loaders like M - * @param event - * @private - */ - p._handleFileError = function (event) { - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, event.item); - this._sendError(newEvent); - }; - - /** - * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} - * is set to `true`. - * @method _handleError - * @param {ErrorEvent} event The error event, containing relevant error information. - * @private - */ - p._handleError = function (event) { - var loader = event.target; - this._numItemsLoaded++; - - this._finishOrderedItem(loader, true); - this._updateProgress(); - - var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem()); - // TODO: Propagate actual error message. - - this._sendError(newEvent); - - if (!this.stopOnError) { - this._removeLoadItem(loader); - this._cleanLoadItem(loader); - this._loadNext(); - } else { - this.setPaused(true); - } - }; - - /** - * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and - * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML, - * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. - * @method _handleFileComplete - * @param {Event} event The event object from the loader. - * @private - */ - p._handleFileComplete = function (event) { - var loader = event.target; - var item = loader.getItem(); - - var result = loader.getResult(); - this._loadedResults[item.id] = result; - var rawResult = loader.getResult(true); - if (rawResult != null && rawResult !== result) { - this._loadedRawResults[item.id] = rawResult; - } - - this._saveLoadedItems(loader); - - // Remove the load item - this._removeLoadItem(loader); - - if (!this._finishOrderedItem(loader)) { - // The item was NOT managed, so process it now - this._processFinishedLoad(item, loader); - } - - // Clean up the load item - this._cleanLoadItem(loader); - }; - - /** - * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}). - * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the - * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}} - * methods. - * @method _saveLoadedItems - * @param {AbstractLoader} loader - * @protected - * @since 0.6.0 - */ - p._saveLoadedItems = function (loader) { - // TODO: Not sure how to handle this. Would be nice to expose the items. - // Loaders may load sub-items. This adds them to this queue - var list = loader.getLoadedItems(); - if (list === null) { - return; - } - - for (var i = 0; i < list.length; i++) { - var item = list[i].item; - - // Store item lookups - this._loadItemsBySrc[item.src] = item; - this._loadItemsById[item.id] = item; - - // Store loaded content - this._loadedResults[item.id] = list[i].result; - this._loadedRawResults[item.id] = list[i].rawResult; - } - }; - - /** - * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if - * so, trigger prior items to trigger as well. - * @method _finishOrderedItem - * @param {AbstractLoader} loader - * @param {Boolean} loadFailed - * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate - * behaviour if it is. - * @private - */ - p._finishOrderedItem = function (loader, loadFailed) { - var item = loader.getItem(); - - if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) - || item.maintainOrder) { - - //TODO: Evaluate removal of the _currentlyLoadingScript - if (loader instanceof createjs.JavaScriptLoader) { - this._currentlyLoadingScript = false; - } - - var index = createjs.indexOf(this._scriptOrder, item); - if (index == -1) { - return false; - } // This loader no longer exists - this._loadedScripts[index] = (loadFailed === true) ? true : item; - - this._checkScriptLoadOrder(); - return true; - } - - return false; - }; - - /** - * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the - * order they were added, but with a "null" value. When they are completed, the value is set to the load item, - * and then when they are processed and dispatched, the value is set to `true`. This method simply - * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are - * dispatched. - * @method _checkScriptLoadOrder - * @private - */ - p._checkScriptLoadOrder = function () { - var l = this._loadedScripts.length; - - for (var i = 0; i < l; i++) { - var item = this._loadedScripts[i]; - if (item === null) { - break; - } // This is still loading. Do not process further. - if (item === true) { - continue; - } // This has completed, and been processed. Move on. - - var loadItem = this._loadedResults[item.id]; - if (item.type == createjs.LoadQueue.JAVASCRIPT) { - // Append script tags to the head automatically. - createjs.DomUtils.appendToHead(loadItem); - } - - var loader = item._loader; - this._processFinishedLoad(item, loader); - this._loadedScripts[i] = true; - } - }; - - /** - * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts - * the next item. - * @method _processFinishedLoad - * @param {LoadItem|Object} item - * @param {AbstractLoader} loader - * @protected - */ - p._processFinishedLoad = function (item, loader) { - this._numItemsLoaded++; - - // Since LoadQueue needs maintain order, we can't append scripts in the loader. - // So we do it here instead. Or in _checkScriptLoadOrder(); - if (!this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) { - var tag = loader.getTag(); - createjs.DomUtils.appendToHead(tag); - } - - this._updateProgress(); - this._sendFileComplete(item, loader); - this._loadNext(); - }; - - /** - * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to - * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before - * the script can even be started, since it exist in the DOM while loading. - * @method _canStartLoad - * @param {AbstractLoader} loader The loader for the item - * @return {Boolean} Whether the item can start a load or not. - * @private - */ - p._canStartLoad = function (loader) { - if (!this.maintainScriptOrder || loader.preferXHR) { - return true; - } - var item = loader.getItem(); - if (item.type != createjs.LoadQueue.JAVASCRIPT) { - return true; - } - if (this._currentlyLoadingScript) { - return false; - } - - var index = this._scriptOrder.indexOf(item); - var i = 0; - while (i < index) { - var checkItem = this._loadedScripts[i]; - if (checkItem == null) { - return false; - } - i++; - } - this._currentlyLoadingScript = true; - return true; - }; - - /** - * A load item is completed or was canceled, and needs to be removed from the LoadQueue. - * @method _removeLoadItem - * @param {AbstractLoader} loader A loader instance to remove. - * @private - */ - p._removeLoadItem = function (loader) { - var l = this._currentLoads.length; - for (var i = 0; i < l; i++) { - if (this._currentLoads[i] == loader) { - this._currentLoads.splice(i, 1); - break; - } - } - }; - - /** - * Remove unneeded references from a loader. - * - * @param loader - * @private - */ - p._cleanLoadItem = function(loader) { - var item = loader.getItem(); - if (item) { - delete item._loader; - } - } - - /** - * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress. - * @method _handleProgress - * @param {ProgressEvent} event The progress event from the item. - * @private - */ - p._handleProgress = function (event) { - var loader = event.target; - this._sendFileProgress(loader.getItem(), loader.progress); - this._updateProgress(); - }; - - /** - * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an - * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before - * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append - * loaded progress on top of the already-loaded items. - * - * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be: - *
      - *
    • 5/10 of the items in the queue (50%)
    • - *
    • plus 20% of item 6's slot (2%)
    • - *
    • equals 52%
    • - *
    - * @method _updateProgress - * @private - */ - p._updateProgress = function () { - var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress - var remaining = this._numItems - this._numItemsLoaded; - if (remaining > 0) { - var chunk = 0; - for (var i = 0, l = this._currentLoads.length; i < l; i++) { - chunk += this._currentLoads[i].progress; - } - loaded += (chunk / remaining) * (remaining / this._numItems); - } - - if (this._lastProgress != loaded) { - this._sendProgress(loaded); - this._lastProgress = loaded; - } - }; - - /** - * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal - * hashes. - * @method _disposeItem - * @param {LoadItem|Object} item The item that was passed in for preloading. - * @private - */ - p._disposeItem = function (item) { - delete this._loadedResults[item.id]; - delete this._loadedRawResults[item.id]; - delete this._loadItemsById[item.id]; - delete this._loadItemsBySrc[item.src]; - }; - - /** - * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendFileProgress - * @param {LoadItem|Object} item The item that is being loaded. - * @param {Number} progress The amount the item has been loaded (between 0 and 1). - * @protected - */ - p._sendFileProgress = function (item, progress) { - if (this._isCanceled() || this._paused) { - return; - } - if (!this.hasEventListener("fileprogress")) { - return; - } - - //LM: Rework ProgressEvent to support this? - var event = new createjs.Event("fileprogress"); - event.progress = progress; - event.loaded = progress; - event.total = 1; - event.item = item; - - this.dispatchEvent(event); - }; - - /** - * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for - * details on the event payload. - * @method _sendFileComplete - * @param {LoadItemObject} item The item that is being loaded. - * @param {AbstractLoader} loader - * @protected - */ - p._sendFileComplete = function (item, loader) { - if (this._isCanceled() || this._paused) { - return; - } - - var event = new createjs.Event("fileload"); - event.loader = loader; - event.item = item; - event.result = this._loadedResults[item.id]; - event.rawResult = this._loadedRawResults[item.id]; - - // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this. - if (item.completeHandler) { - item.completeHandler(event); - } - - this.hasEventListener("fileload") && this.dispatchEvent(event); - }; - - /** - * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see - * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload. - * @method _sendFileStart - * @param {LoadItem|Object} item The item that is being loaded. - * @protected - */ - p._sendFileStart = function (item) { - var event = new createjs.Event("filestart"); - event.item = item; - this.hasEventListener("filestart") && this.dispatchEvent(event); - }; - - p.toString = function () { - return "[PreloadJS LoadQueue]"; - }; - - createjs.LoadQueue = createjs.promote(LoadQueue, "AbstractLoader"); -}()); - -//############################################################################## -// TextLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for Text files. - * @class TextLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function TextLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.TEXT); - }; - - var p = createjs.extend(TextLoader, createjs.AbstractLoader); - var s = TextLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader loads items that are of type {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}, - * but is also the default loader if a file type can not be determined. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.TEXT; - }; - - createjs.TextLoader = createjs.promote(TextLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// BinaryLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for binary files. This is useful for loading web audio, or content that requires an ArrayBuffer. - * @class BinaryLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function BinaryLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.BINARY); - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(BinaryLoader, createjs.AbstractLoader); - var s = BinaryLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.BINARY; - }; - - // private methods - /** - * Before the item loads, set the response type to "arraybuffer" - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - event.loader.setResponseType("arraybuffer"); - }; - - createjs.BinaryLoader = createjs.promote(BinaryLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// CSSLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for CSS files. - * @class CSSLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function CSSLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.CSS); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "href"; - - if (preferXHR) { - this._tag = document.createElement("style"); - } else { - this._tag = document.createElement("link"); - } - - this._tag.rel = "stylesheet"; - this._tag.type = "text/css"; - }; - - var p = createjs.extend(CSSLoader, createjs.AbstractLoader); - var s = CSSLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.CSS; - }; - - // protected methods - /** - * The result formatter for CSS files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - if (this._preferXHR) { - var tag = loader.getTag(); - - if (tag.styleSheet) { // IE - tag.styleSheet.cssText = loader.getResult(true); - } else { - var textNode = document.createTextNode(loader.getResult(true)); - tag.appendChild(textNode); - } - } else { - tag = this._tag; - } - - createjs.DomUtils.appendToHead(tag); - - return tag; - }; - - createjs.CSSLoader = createjs.promote(CSSLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// ImageLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for image files. - * @class ImageLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function ImageLoader (loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.IMAGE); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - // Check if the preload item is already a tag. - if (createjs.RequestUtils.isImageTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isImageTag(loadItem.src)) { - this._tag = loadItem.src; - } else if (createjs.RequestUtils.isImageTag(loadItem.tag)) { - this._tag = loadItem.tag; - } - - if (this._tag != null) { - this._preferXHR = false; - } else { - this._tag = document.createElement("img"); - } - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(ImageLoader, createjs.AbstractLoader); - var s = ImageLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.IMAGE; - }; - - // public methods - p.load = function () { - if (this._tag.src != "" && this._tag.complete) { - this._sendComplete(); - return; - } - - var crossOrigin = this._item.crossOrigin; - if (crossOrigin == true) { crossOrigin = "Anonymous"; } - if (crossOrigin != null && !createjs.RequestUtils.isLocal(this._item.src)) { - this._tag.crossOrigin = crossOrigin; - } - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - event.loader.mimeType = 'text/plain; charset=x-user-defined-binary'; - - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for Image files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLImageElement} - * @private - */ - p._formatResult = function (loader) { - return this._formatImage; - }; - - /** - * The asynchronous image formatter function. This is required because images have - * a short delay before they are ready. - * @method _formatImage - * @param {Function} successCallback The method to call when the result has finished formatting - * @param {Function} errorCallback The method to call if an error occurs during formatting - * @private - */ - p._formatImage = function (successCallback, errorCallback) { - var tag = this._tag; - var URL = window.URL || window.webkitURL; - - if (!this._preferXHR) { - //document.body.removeChild(tag); - } else if (URL) { - var objURL = URL.createObjectURL(this.getResult(true)); - tag.src = objURL; - - tag.addEventListener("load", this._cleanUpURL, false); - tag.addEventListener("error", this._cleanUpURL, false); - } else { - tag.src = this._item.src; - } - - if (tag.complete) { - successCallback(tag); - } else { - tag.onload = createjs.proxy(function() { - successCallback(this._tag); - }, this); - - tag.onerror = createjs.proxy(function() { - errorCallback(_this._tag); - }, this); - } - }; - - /** - * Clean up the ObjectURL, the tag is done with it. Note that this function is run - * as an event listener without a proxy/closure, as it doesn't require it - so do not - * include any functionality that requires scope without changing it. - * @method _cleanUpURL - * @param event - * @private - */ - p._cleanUpURL = function (event) { - var URL = window.URL || window.webkitURL; - URL.revokeObjectURL(event.target.src); - }; - - createjs.ImageLoader = createjs.promote(ImageLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JavaScriptLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JavaScript files. - * @class JavaScriptLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function JavaScriptLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.JAVASCRIPT); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - this.setTag(document.createElement("script")); - }; - - var p = createjs.extend(JavaScriptLoader, createjs.AbstractLoader); - var s = JavaScriptLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JAVASCRIPT; - }; - - // protected methods - /** - * The result formatter for JavaScript files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - var tag = loader.getTag(); - if (this._preferXHR) { - tag.text = loader.getResult(true); - } - return tag; - }; - - createjs.JavaScriptLoader = createjs.promote(JavaScriptLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JSONLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSON files. To load JSON cross-domain, use JSONP and the {{#crossLink "JSONPLoader"}}{{/crossLink}} - * instead. To load JSON-formatted manifests, use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to - * load EaselJS SpriteSheets, use {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. - * @class JSONLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function JSONLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.JSON); - - // public properties - this.resultFormatter = this._formatResult; - }; - - var p = createjs.extend(JSONLoader, createjs.AbstractLoader); - var s = JSONLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JSON; - }; - - // protected methods - /** - * The result formatter for JSON files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLLinkElement|HTMLStyleElement} - * @private - */ - p._formatResult = function (loader) { - var json = null; - try { - json = createjs.DataUtils.parseJSON(loader.getResult(true)); - } catch (e) { - var event = new createjs.ErrorEvent("JSON_FORMAT", null, e); - this._sendError(event); - return e; - } - - return json; - }; - - createjs.JSONLoader = createjs.promote(JSONLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// JSONPLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSONP files, which are JSON-formatted text files, wrapped in a callback. To load regular JSON - * without a callback use the {{#crossLink "JSONLoader"}}{{/crossLink}} instead. To load JSON-formatted manifests, - * use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to load EaselJS SpriteSheets, use - * {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}. - * - * JSONP is a format that provides a solution for loading JSON files cross-domain without requiring CORS. - * JSONP files are loaded as JavaScript, and the "callback" is executed once they are loaded. The callback in the - * JSONP must match the callback passed to the loadItem. - * - *

    Example JSONP

    - * - * callbackName({ - * "name": "value", - * "num": 3, - * "obj": { "bool":true } - * }); - * - *

    Example

    - * - * var loadItem = {id:"json", type:"jsonp", src:"http://server.com/text.json", callback:"callbackName"} - * var queue = new createjs.LoadQueue(); - * queue.on("complete", handleComplete); - * queue.loadItem(loadItem); - * - * function handleComplete(event) } - * var json = queue.getResult("json"); - * console.log(json.obj.bool); // true - * } - * - * Note that JSONP files loaded concurrently require a unique callback. To ensure JSONP files are loaded - * in order, either use the {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} method (set to 1), - * or set {{#crossLink "LoadItem/maintainOrder:property"}}{{/crossLink}} on items with the same callback. - * - * @class JSONPLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function JSONPLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, false, createjs.AbstractLoader.JSONP); - this.setTag(document.createElement("script")); - this.getTag().type = "text/javascript"; - }; - - var p = createjs.extend(JSONPLoader, createjs.AbstractLoader); - var s = JSONPLoader; - - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.JSONP; - }; - - // public methods - p.cancel = function () { - this.AbstractLoader_cancel(); - this._dispose(); - }; - - /** - * Loads the JSONp file. Because of the unique loading needs of JSONp - * we don't use the AbstractLoader.load() method. - * - * @method load - * - */ - p.load = function () { - if (this._item.callback == null) { - throw new Error('callback is required for loading JSONP requests.'); - } - - // TODO: Look into creating our own iFrame to handle the load - // In the first attempt, FF did not get the result - // result instanceof Object did not work either - // so we would need to clone the result. - if (window[this._item.callback] != null) { - throw new Error( - "JSONP callback '" + - this._item.callback + - "' already exists on window. You need to specify a different callback or re-name the current one."); - } - - window[this._item.callback] = createjs.proxy(this._handleLoad, this); - window.document.body.appendChild(this._tag); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - // Load the tag - this._tag.src = this._item.src; - }; - - // private methods - /** - * Handle the JSONP callback, which is a public method defined on `window`. - * @method _handleLoad - * @param {Object} data The formatted JSON data. - * @private - */ - p._handleLoad = function (data) { - this._result = this._rawResult = data; - this._sendComplete(); - - this._dispose(); - }; - - /** - * The tag request has not loaded within the time specfied in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleTimeout = function () { - this._dispose(); - this.dispatchEvent(new createjs.ErrorEvent("timeout")); - }; - - /** - * Clean up the JSONP load. This clears out the callback and script tag that this loader creates. - * @method _dispose - * @private - */ - p._dispose = function () { - window.document.body.removeChild(this._tag); - delete window[this._item.callback]; - - clearTimeout(this._loadTimeout); - }; - - createjs.JSONPLoader = createjs.promote(JSONPLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// ManifestLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for JSON manifests. Items inside the manifest are loaded before the loader completes. To load manifests - * using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} as part of the - * {{#crossLink "LoadItem"}}{{/crossLink}}. - * - * The list of files in the manifest must be defined on the top-level JSON object in a `manifest` property. This - * example shows a sample manifest definition, as well as how to to include a sub-manifest. - * - * { - * "path": "assets/", - * "manifest": [ - * "image.png", - * {"src": "image2.png", "id":"image2"}, - * {"src": "sub-manifest.json", "type":"manifest", "callback":"jsonCallback"} - * ] - * } - * - * When a ManifestLoader has completed loading, the parent loader (usually a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but could also be another ManifestLoader) will inherit all the loaded items, so you can access them directly. - * - * Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} and {{#crossLink "JSONPLoader"}}{{/crossLink}} are - * higher priority loaders, so manifests must set the {{#crossLink "LoadItem"}}{{/crossLink}} - * {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property to {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}. - * @class ManifestLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function ManifestLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, null, createjs.AbstractLoader.MANIFEST); - - // Public Properties - /** - * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}, - * used to pass plugins to new LoadQueues that may be created. - * @property _plugins - * @type {Array} - * @private - * @since 0.6.1 - */ - this.plugins = null; - - - // Protected Properties - /** - * An internal {{#crossLink "LoadQueue"}}{{/crossLink}} that loads the contents of the manifest. - * @property _manifestQueue - * @type {LoadQueue} - * @private - */ - this._manifestQueue = null; - }; - - var p = createjs.extend(ManifestLoader, createjs.AbstractLoader); - var s = ManifestLoader; - - // static properties - /** - * The amount of progress that the manifest itself takes up. - * @property MANIFEST_PROGRESS - * @type {number} - * @default 0.25 (25%) - * @private - * @static - */ - s.MANIFEST_PROGRESS = 0.25; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.MANIFEST; - }; - - // public methods - p.load = function () { - this.AbstractLoader_load(); - }; - - // protected methods - p._createRequest = function() { - var callback = this._item.callback; - if (callback != null) { - this._request = new createjs.JSONPLoader(this._item); - } else { - this._request = new createjs.JSONLoader(this._item); - } - }; - - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target.getResult(true); - this._result = event.target.getResult(); - this._sendProgress(s.MANIFEST_PROGRESS); - this._loadManifest(this._result); - return; - case "progress": - event.loaded *= s.MANIFEST_PROGRESS; - this.progress = event.loaded / event.total; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - this._sendProgress(event); - return; - } - this.AbstractLoader_handleEvent(event); - }; - - p.destroy = function() { - this.AbstractLoader_destroy(); - this._manifestQueue.close(); - }; - - /** - * Create and load the manifest items once the actual manifest has been loaded. - * @method _loadManifest - * @param {Object} json - * @private - */ - p._loadManifest = function (json) { - if (json && json.manifest) { - var queue = this._manifestQueue = new createjs.LoadQueue(); - queue.on("fileload", this._handleManifestFileLoad, this); - queue.on("progress", this._handleManifestProgress, this); - queue.on("complete", this._handleManifestComplete, this, true); - queue.on("error", this._handleManifestError, this, true); - for(var i = 0, l = this.plugins.length; i < l; i++) { // conserve order of plugins - queue.installPlugin(this.plugins[i]); - } - queue.loadManifest(json); - } else { - this._sendComplete(); - } - }; - - /** - * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed. - * @method _handleManifestFileLoad - * @param {Event} event - * @private - */ - p._handleManifestFileLoad = function (event) { - event.target = null; - this.dispatchEvent(event); - }; - - /** - * The manifest has completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} - * {{#crossLink "Event"}}{{/crossLink}} from the ManifestLoader. - * @method _handleManifestComplete - * @param {Event} event - * @private - */ - p._handleManifestComplete = function (event) { - this._loadedItems = this._manifestQueue.getItems(true); - this._sendComplete(); - }; - - /** - * The manifest has reported progress. - * @method _handleManifestProgress - * @param {ProgressEvent} event - * @private - */ - p._handleManifestProgress = function (event) { - this.progress = event.progress * (1 - s.MANIFEST_PROGRESS) + s.MANIFEST_PROGRESS; - this._sendProgress(this.progress); - }; - - /** - * The manifest has reported an error with one of the files. - * @method _handleManifestError - * @param {ErrorEvent} event - * @private - */ - p._handleManifestError = function (event) { - var newEvent = new createjs.Event("fileerror"); - newEvent.item = event.data; - this.dispatchEvent(newEvent); - }; - - createjs.ManifestLoader = createjs.promote(ManifestLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// SoundLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which - * should be created by either a library playing the sound (such as SoundJS, or an - * external framework that handles audio playback. To load content that can be played by WebAudio, use the - * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually. - * @class SoundLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractMediaLoader - * @constructor - */ - function SoundLoader(loadItem, preferXHR) { - this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND); - - // protected properties - if (createjs.RequestUtils.isAudioTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) { - this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src; - } - - if (this._tag != null) { - this._preferXHR = false; - } - }; - - var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader); - var s = SoundLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SOUND; - }; - - // protected methods - p._createTag = function (src) { - var tag = document.createElement("audio"); - tag.autoplay = false; - tag.preload = "none"; - - //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works. - tag.src = src; - return tag; - }; - - createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader"); - -}()); - -//############################################################################## -// VideoLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for video files. - * @class VideoLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractMediaLoader - * @constructor - */ - function VideoLoader(loadItem, preferXHR) { - this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.VIDEO); - - if (createjs.RequestUtils.isVideoTag(loadItem) || createjs.RequestUtils.isVideoTag(loadItem.src)) { - this.setTag(createjs.RequestUtils.isVideoTag(loadItem)?loadItem:loadItem.src); - - // We can't use XHR for a tag that's passed in. - this._preferXHR = false; - } else { - this.setTag(this._createTag()); - } - }; - - var p = createjs.extend(VideoLoader, createjs.AbstractMediaLoader); - var s = VideoLoader; - - /** - * Create a new video tag - * - * @returns {HTMLElement} - * @private - */ - p._createTag = function () { - return document.createElement("video"); - }; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.VIDEO; - }; - - createjs.VideoLoader = createjs.promote(VideoLoader, "AbstractMediaLoader"); - -}()); - -//############################################################################## -// SpriteSheetLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for EaselJS SpriteSheets. Images inside the spritesheet definition are loaded before the loader - * completes. To load SpriteSheets using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} - * as part of the {{#crossLink "LoadItem"}}{{/crossLink}}. Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} - * and {{#crossLink "JSONPLoader"}}{{/crossLink}} are higher priority loaders, so SpriteSheets must - * set the {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property - * to {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}. - * - * The {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/crossOrigin:property"}}{{/crossLink}} as well - * as the {{#crossLink "LoadQueue's"}}{{/crossLink}} `basePath` argument and {{#crossLink "LoadQueue/_preferXHR"}}{{/crossLink}} - * property supplied to the {{#crossLink "LoadQueue"}}{{/crossLink}} are passed on to the sub-manifest that loads - * the SpriteSheet images. - * - * Note that the SpriteSheet JSON does not respect the {{#crossLink "LoadQueue/_preferXHR:property"}}{{/crossLink}} - * property, which should instead be determined by the presence of a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} - * property on the SpriteSheet load item. This is because the JSON loaded will have a different format depending on - * if it is loaded as JSON, so just changing `preferXHR` is not enough to change how it is loaded. - * @class SpriteSheetLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function SpriteSheetLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SPRITESHEET); - - // protected properties - /** - * An internal queue which loads the SpriteSheet's images. - * @method _manifestQueue - * @type {LoadQueue} - * @private - */ - this._manifestQueue = null; - } - - var p = createjs.extend(SpriteSheetLoader, createjs.AbstractLoader); - var s = SpriteSheetLoader; - - // static properties - /** - * The amount of progress that the manifest itself takes up. - * @property SPRITESHEET_PROGRESS - * @type {number} - * @default 0.25 (25%) - * @private - * @static - */ - s.SPRITESHEET_PROGRESS = 0.25; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SPRITESHEET; - }; - - // public methods - p.destroy = function() { - this.AbstractLoader_destroy; - this._manifestQueue.close(); - }; - - // protected methods - p._createRequest = function() { - var callback = this._item.callback; - if (callback != null) { - this._request = new createjs.JSONPLoader(this._item); - } else { - this._request = new createjs.JSONLoader(this._item); - } - }; - - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target.getResult(true); - this._result = event.target.getResult(); - this._sendProgress(s.SPRITESHEET_PROGRESS); - this._loadManifest(this._result); - return; - case "progress": - event.loaded *= s.SPRITESHEET_PROGRESS; - this.progress = event.loaded / event.total; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - this._sendProgress(event); - return; - } - this.AbstractLoader_handleEvent(event); - }; - - /** - * Create and load the images once the SpriteSheet JSON has been loaded. - * @method _loadManifest - * @param {Object} json - * @private - */ - p._loadManifest = function (json) { - if (json && json.images) { - var queue = this._manifestQueue = new createjs.LoadQueue(this._preferXHR, this._item.path, this._item.crossOrigin); - queue.on("complete", this._handleManifestComplete, this, true); - queue.on("fileload", this._handleManifestFileLoad, this); - queue.on("progress", this._handleManifestProgress, this); - queue.on("error", this._handleManifestError, this, true); - queue.loadManifest(json.images); - } - }; - - /** - * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed. - * @method _handleManifestFileLoad - * @param {Event} event - * @private - */ - p._handleManifestFileLoad = function (event) { - var image = event.result; - if (image != null) { - var images = this.getResult().images; - var pos = images.indexOf(event.item.src); - images[pos] = image; - } - }; - - /** - * The images have completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} - * {{#crossLink "Event"}}{{/crossLink}} from the SpriteSheetLoader. - * @method _handleManifestComplete - * @param {Event} event - * @private - */ - p._handleManifestComplete = function (event) { - this._result = new createjs.SpriteSheet(this._result); - this._loadedItems = this._manifestQueue.getItems(true); - this._sendComplete(); - }; - - /** - * The images {{#crossLink "LoadQueue"}}{{/crossLink}} has reported progress. - * @method _handleManifestProgress - * @param {ProgressEvent} event - * @private - */ - p._handleManifestProgress = function (event) { - this.progress = event.progress * (1 - s.SPRITESHEET_PROGRESS) + s.SPRITESHEET_PROGRESS; - this._sendProgress(this.progress); - }; - - /** - * An image has reported an error. - * @method _handleManifestError - * @param {ErrorEvent} event - * @private - */ - p._handleManifestError = function (event) { - var newEvent = new createjs.Event("fileerror"); - newEvent.item = event.data; - this.dispatchEvent(newEvent); - }; - - createjs.SpriteSheetLoader = createjs.promote(SpriteSheetLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// SVGLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for SVG files. - * @class SVGLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractLoader - * @constructor - */ - function SVGLoader(loadItem, preferXHR) { - this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SVG); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "data"; - - if (preferXHR) { - this.setTag(document.createElement("svg")); - } else { - this.setTag(document.createElement("object")); - this.getTag().type = "image/svg+xml"; - } - }; - - var p = createjs.extend(SVGLoader, createjs.AbstractLoader); - var s = SVGLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SVG; - }; - - // protected methods - /** - * The result formatter for SVG files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {Object} - * @private - */ - p._formatResult = function (loader) { - // mime should be image/svg+xml, but Opera requires text/xml - var xml = createjs.DataUtils.parseXML(loader.getResult(true), "text/xml"); - var tag = loader.getTag(); - - if (!this._preferXHR && document.body.contains(tag)) { - document.body.removeChild(tag); - } - - if (xml.documentElement != null) { - tag.appendChild(xml.documentElement); - tag.style.visibility = "visible"; - return tag; - } else { // For browsers that don't support SVG, just give them the XML. (IE 9-8) - return xml; - } - }; - - createjs.SVGLoader = createjs.promote(SVGLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// XMLLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for CSS files. - * @class XMLLoader - * @param {LoadItem|Object} loadItem - * @extends AbstractLoader - * @constructor - */ - function XMLLoader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.XML); - - // public properties - this.resultFormatter = this._formatResult; - }; - - var p = createjs.extend(XMLLoader, createjs.AbstractLoader); - var s = XMLLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.XML; - }; - - // protected methods - /** - * The result formatter for XML files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {XMLDocument} - * @private - */ - p._formatResult = function (loader) { - return createjs.DataUtils.parseXML(loader.getResult(true), "text/xml"); - }; - - createjs.XMLLoader = createjs.promote(XMLLoader, "AbstractLoader"); - -}()); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js b/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js deleted file mode 100644 index 6f898e826e..0000000000 --- a/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js +++ /dev/null @@ -1,7949 +0,0 @@ -/*! -* SoundJS -* Visit http://createjs.com/ for documentation, updates and examples. -* -* Copyright (c) 2010 gskinner.com, inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -* OTHER DEALINGS IN THE SOFTWARE. -*/ - - -//############################################################################## -// version.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - - /** - * Static class holding library specific information such as the version and buildDate of the library. - * The SoundJS class has been renamed {{#crossLink "Sound"}}{{/crossLink}}. Please see {{#crossLink "Sound"}}{{/crossLink}} - * for information on using sound. - * @class SoundJS - **/ - var s = createjs.SoundJS = createjs.SoundJS || {}; - - /** - * The version string for this release. - * @property version - * @type String - * @static - **/ - s.version = /*=version*/"NEXT"; // injected by build process - - /** - * The build date for this release in UTC format. - * @property buildDate - * @type String - * @static - **/ - s.buildDate = /*=date*/"Fri, 04 Dec 2015 17:24:04 GMT"; // injected by build process - -})(); - -//############################################################################## -// extend.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Sets up the prototype chain and constructor property for a new class. - * - * This should be called right after creating the class constructor. - * - * function MySubClass() {} - * createjs.extend(MySubClass, MySuperClass); - * MySubClass.prototype.doSomething = function() { } - * - * var foo = new MySubClass(); - * console.log(foo instanceof MySuperClass); // true - * console.log(foo.prototype.constructor === MySubClass); // true - * - * @method extend - * @param {Function} subclass The subclass. - * @param {Function} superclass The superclass to extend. - * @return {Function} Returns the subclass's new prototype. - */ -createjs.extend = function(subclass, superclass) { - "use strict"; - - function o() { this.constructor = subclass; } - o.prototype = superclass.prototype; - return (subclass.prototype = new o()); -}; - -//############################################################################## -// promote.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`. - * It is recommended to use the super class's name as the prefix. - * An alias to the super class's constructor is always added in the format `prefix_constructor`. - * This allows the subclass to call super class methods without using `function.call`, providing better performance. - * - * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")` - * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the - * prototype of `MySubClass` as `MySuperClass_draw`. - * - * This should be called after the class's prototype is fully defined. - * - * function ClassA(name) { - * this.name = name; - * } - * ClassA.prototype.greet = function() { - * return "Hello "+this.name; - * } - * - * function ClassB(name, punctuation) { - * this.ClassA_constructor(name); - * this.punctuation = punctuation; - * } - * createjs.extend(ClassB, ClassA); - * ClassB.prototype.greet = function() { - * return this.ClassA_greet()+this.punctuation; - * } - * createjs.promote(ClassB, "ClassA"); - * - * var foo = new ClassB("World", "!?!"); - * console.log(foo.greet()); // Hello World!?! - * - * @method promote - * @param {Function} subclass The class to promote super class methods on. - * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass. - * @return {Function} Returns the subclass. - */ -createjs.promote = function(subclass, prefix) { - "use strict"; - - var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__; - if (supP) { - subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable - for (var n in supP) { - if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; } - } - } - return subclass; -}; - -//############################################################################## -// IndexOf.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ - -/** - * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of - * that value. Returns -1 if value is not found. - * - * var i = createjs.indexOf(myArray, myElementToFind); - * - * @method indexOf - * @param {Array} array Array to search for searchElement - * @param searchElement Element to find in array. - * @return {Number} The first index of searchElement in array. - */ -createjs.indexOf = function (array, searchElement){ - "use strict"; - - for (var i = 0,l=array.length; i < l; i++) { - if (searchElement === array[i]) { - return i; - } - } - return -1; -}; - -//############################################################################## -// Proxy.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the - * createjs namespace directly. - * - *

    Example

    - * - * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); - * - * @class Utility Methods - * @main Utility Methods - */ - -(function() { - "use strict"; - - /** - * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a - * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the - * method gets called in the correct scope. - * - * Additional arguments can be passed that will be applied to the function when it is called. - * - *

    Example

    - * - * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); - * - * function myHandler(arg1, arg2) { - * // This gets called when myObject.myCallback is executed. - * } - * - * @method proxy - * @param {Function} method The function to call - * @param {Object} scope The scope to call the method name on - * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. - * @public - * @static - */ - createjs.proxy = function (method, scope) { - var aArgs = Array.prototype.slice.call(arguments, 2); - return function () { - return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); - }; - } - -}()); - -//############################################################################## -// BrowserDetect.js -//############################################################################## - -this.createjs = this.createjs||{}; - -/** - * @class Utility Methods - */ -(function() { - "use strict"; - - /** - * An object that determines the current browser, version, operating system, and other environment - * variables via user agent string. - * - * Used for audio because feature detection is unable to detect the many limitations of mobile devices. - * - *

    Example

    - * - * if (createjs.BrowserDetect.isIOS) { // do stuff } - * - * @property BrowserDetect - * @type {Object} - * @param {Boolean} isFirefox True if our browser is Firefox. - * @param {Boolean} isOpera True if our browser is opera. - * @param {Boolean} isChrome True if our browser is Chrome. Note that Chrome for Android returns true, but is a - * completely different browser with different abilities. - * @param {Boolean} isIOS True if our browser is safari for iOS devices (iPad, iPhone, and iPod). - * @param {Boolean} isAndroid True if our browser is Android. - * @param {Boolean} isBlackberry True if our browser is Blackberry. - * @constructor - * @static - */ - function BrowserDetect() { - throw "BrowserDetect cannot be instantiated"; - }; - - var agent = BrowserDetect.agent = window.navigator.userAgent; - BrowserDetect.isWindowPhone = (agent.indexOf("IEMobile") > -1) || (agent.indexOf("Windows Phone") > -1); - BrowserDetect.isFirefox = (agent.indexOf("Firefox") > -1); - BrowserDetect.isOpera = (window.opera != null); - BrowserDetect.isChrome = (agent.indexOf("Chrome") > -1); // NOTE that Chrome on Android returns true but is a completely different browser with different abilities - BrowserDetect.isIOS = (agent.indexOf("iPod") > -1 || agent.indexOf("iPhone") > -1 || agent.indexOf("iPad") > -1) && !BrowserDetect.isWindowPhone; - BrowserDetect.isAndroid = (agent.indexOf("Android") > -1) && !BrowserDetect.isWindowPhone; - BrowserDetect.isBlackberry = (agent.indexOf("Blackberry") > -1); - - createjs.BrowserDetect = BrowserDetect; - -}()); - -//############################################################################## -// EventDispatcher.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - -// constructor: - /** - * EventDispatcher provides methods for managing queues of event listeners and dispatching events. - * - * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the - * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. - * - * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the - * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports - * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. - * - * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier - * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The - * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to - * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. - * - * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} - * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also - * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. - * - *

    Example

    - * Add EventDispatcher capabilities to the "MyClass" class. - * - * EventDispatcher.initialize(MyClass.prototype); - * - * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). - * - * instance.addEventListener("eventName", handlerMethod); - * function handlerMethod(event) { - * console.log(event.target + " Was Clicked"); - * } - * - * Maintaining proper scope
    - * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} - * method to subscribe to events simplifies this. - * - * instance.addEventListener("click", function(event) { - * console.log(instance == this); // false, scope is ambiguous. - * }); - * - * instance.on("click", function(event) { - * console.log(instance == this); // true, "on" uses dispatcher scope by default. - * }); - * - * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage - * scope. - * - * Browser support - * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model - * requires modern browsers (IE9+). - * - * - * @class EventDispatcher - * @constructor - **/ - function EventDispatcher() { - - - // private properties: - /** - * @protected - * @property _listeners - * @type Object - **/ - this._listeners = null; - - /** - * @protected - * @property _captureListeners - * @type Object - **/ - this._captureListeners = null; - } - var p = EventDispatcher.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// static public methods: - /** - * Static initializer to mix EventDispatcher methods into a target object or prototype. - * - * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class - * EventDispatcher.initialize(myObject); // add to a specific instance - * - * @method initialize - * @static - * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a - * prototype. - **/ - EventDispatcher.initialize = function(target) { - target.addEventListener = p.addEventListener; - target.on = p.on; - target.removeEventListener = target.off = p.removeEventListener; - target.removeAllEventListeners = p.removeAllEventListeners; - target.hasEventListener = p.hasEventListener; - target.dispatchEvent = p.dispatchEvent; - target._dispatchEvent = p._dispatchEvent; - target.willTrigger = p.willTrigger; - }; - - -// public methods: - /** - * Adds the specified event listener. Note that adding multiple listeners to the same function will result in - * multiple callbacks getting fired. - * - *

    Example

    - * - * displayObject.addEventListener("click", handleClick); - * function handleClick(event) { - * // Click happened. - * } - * - * @method addEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function | Object} Returns the listener for chaining or assignment. - **/ - p.addEventListener = function(type, listener, useCapture) { - var listeners; - if (useCapture) { - listeners = this._captureListeners = this._captureListeners||{}; - } else { - listeners = this._listeners = this._listeners||{}; - } - var arr = listeners[type]; - if (arr) { this.removeEventListener(type, listener, useCapture); } - arr = listeners[type]; // remove may have deleted the array - if (!arr) { listeners[type] = [listener]; } - else { arr.push(listener); } - return listener; - }; - - /** - * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener - * only run once, associate arbitrary data with the listener, and remove the listener. - * - * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. - * The wrapper function is returned for use with `removeEventListener` (or `off`). - * - * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use - * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls - * to `on` with the same params will create multiple listeners. - * - *

    Example

    - * - * var listener = myBtn.on("click", handleClick, null, false, {count:3}); - * function handleClick(evt, data) { - * data.count -= 1; - * console.log(this == myBtn); // true - scope defaults to the dispatcher - * if (data.count == 0) { - * alert("clicked 3 times!"); - * myBtn.off("click", listener); - * // alternately: evt.remove(); - * } - * } - * - * @method on - * @param {String} type The string type of the event. - * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when - * the event is dispatched. - * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). - * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. - * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. - * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. - **/ - p.on = function(type, listener, scope, once, data, useCapture) { - if (listener.handleEvent) { - scope = scope||listener; - listener = listener.handleEvent; - } - scope = scope||this; - return this.addEventListener(type, function(evt) { - listener.call(scope, evt, data); - once&&evt.remove(); - }, useCapture); - }; - - /** - * Removes the specified event listener. - * - * Important Note: that you must pass the exact function reference used when the event was added. If a proxy - * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or - * closure will not work. - * - *

    Example

    - * - * displayObject.removeEventListener("click", handleClick); - * - * @method removeEventListener - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.removeEventListener = function(type, listener, useCapture) { - var listeners = useCapture ? this._captureListeners : this._listeners; - if (!listeners) { return; } - var arr = listeners[type]; - if (!arr) { return; } - for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See - * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example. - * - * @method off - * @param {String} type The string type of the event. - * @param {Function | Object} listener The listener function or object. - * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. - **/ - p.off = p.removeEventListener; - - /** - * Removes all listeners for the specified type, or all listeners of all types. - * - *

    Example

    - * - * // Remove all listeners - * displayObject.removeAllEventListeners(); - * - * // Remove all click listeners - * displayObject.removeAllEventListeners("click"); - * - * @method removeAllEventListeners - * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. - **/ - p.removeAllEventListeners = function(type) { - if (!type) { this._listeners = this._captureListeners = null; } - else { - if (this._listeners) { delete(this._listeners[type]); } - if (this._captureListeners) { delete(this._captureListeners[type]); } - } - }; - - /** - * Dispatches the specified event to all listeners. - * - *

    Example

    - * - * // Use a string event - * this.dispatchEvent("complete"); - * - * // Use an Event instance - * var event = new createjs.Event("progress"); - * this.dispatchEvent(event); - * - * @method dispatchEvent - * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. - * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, - * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can - * be used to avoid event object instantiation for non-bubbling events that may not have any listeners. - * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj. - * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj. - * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise. - **/ - p.dispatchEvent = function(eventObj, bubbles, cancelable) { - if (typeof eventObj == "string") { - // skip everything if there's no listeners and it doesn't bubble: - var listeners = this._listeners; - if (!bubbles && (!listeners || !listeners[eventObj])) { return true; } - eventObj = new createjs.Event(eventObj, bubbles, cancelable); - } else if (eventObj.target && eventObj.clone) { - // redispatching an active event object, so clone it: - eventObj = eventObj.clone(); - } - - // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent - try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events - - if (!eventObj.bubbles || !this.parent) { - this._dispatchEvent(eventObj, 2); - } else { - var top=this, list=[top]; - while (top.parent) { list.push(top = top.parent); } - var i, l=list.length; - - // capture & atTarget - for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) { - list[i]._dispatchEvent(eventObj, 1+(i==0)); - } - // bubbling - for (i=1; i - *
  • capture phase: starting from the top parent to the target
  • - *
  • at target phase: currently being dispatched from the target
  • - *
  • bubbling phase: from the target to the top parent
  • - * - * @property eventPhase - * @type Number - * @default 0 - * @readonly - */ - this.eventPhase = 0; - - /** - * Indicates whether the event will bubble through the display list. - * @property bubbles - * @type Boolean - * @default false - * @readonly - */ - this.bubbles = !!bubbles; - - /** - * Indicates whether the default behaviour of this event can be cancelled via - * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. - * @property cancelable - * @type Boolean - * @default false - * @readonly - */ - this.cancelable = !!cancelable; - - /** - * The epoch time at which this event was created. - * @property timeStamp - * @type Number - * @default 0 - * @readonly - */ - this.timeStamp = (new Date()).getTime(); - - /** - * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called - * on this event. - * @property defaultPrevented - * @type Boolean - * @default false - * @readonly - */ - this.defaultPrevented = false; - - /** - * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or - * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. - * @property propagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.propagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called - * on this event. - * @property immediatePropagationStopped - * @type Boolean - * @default false - * @readonly - */ - this.immediatePropagationStopped = false; - - /** - * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. - * @property removed - * @type Boolean - * @default false - * @readonly - */ - this.removed = false; - } - var p = Event.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - -// public methods: - /** - * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable. - * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will - * cancel the default behaviour associated with the event. - * @method preventDefault - **/ - p.preventDefault = function() { - this.defaultPrevented = this.cancelable&&true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopPropagation - **/ - p.stopPropagation = function() { - this.propagationStopped = true; - }; - - /** - * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and - * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. - * Mirrors the DOM event standard. - * @method stopImmediatePropagation - **/ - p.stopImmediatePropagation = function() { - this.immediatePropagationStopped = this.propagationStopped = true; - }; - - /** - * Causes the active listener to be removed via removeEventListener(); - * - * myBtn.addEventListener("click", function(evt) { - * // do stuff... - * evt.remove(); // removes this listener. - * }); - * - * @method remove - **/ - p.remove = function() { - this.removed = true; - }; - - /** - * Returns a clone of the Event instance. - * @method clone - * @return {Event} a clone of the Event instance. - **/ - p.clone = function() { - return new Event(this.type, this.bubbles, this.cancelable); - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - * @method set - * @param {Object} props A generic object containing properties to copy to the instance. - * @return {Event} Returns the instance the method is called on (useful for chaining calls.) - * @chainable - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - /** - * Returns a string representation of this object. - * @method toString - * @return {String} a string representation of the instance. - **/ - p.toString = function() { - return "[Event (type="+this.type+")]"; - }; - - createjs.Event = Event; -}()); - -//############################################################################## -// ErrorEvent.js -//############################################################################## - -this.createjs = this.createjs||{}; - -(function() { - "use strict"; - - /** - * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details. - * @class ErrorEvent - * @param {String} [title] The error title - * @param {String} [message] The error description - * @param {Object} [data] Additional error data - * @constructor - */ - function ErrorEvent(title, message, data) { - this.Event_constructor("error"); - - /** - * The short error title, which indicates the type of error that occurred. - * @property title - * @type String - */ - this.title = title; - - /** - * The verbose error message, containing details about the error. - * @property message - * @type String - */ - this.message = message; - - /** - * Additional data attached to an error. - * @property data - * @type {Object} - */ - this.data = data; - } - - var p = createjs.extend(ErrorEvent, createjs.Event); - - p.clone = function() { - return new createjs.ErrorEvent(this.title, this.message, this.data); - }; - - createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event"); - -}()); - -//############################################################################## -// ProgressEvent.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function (scope) { - "use strict"; - - // constructor - /** - * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes. - * @class ProgressEvent - * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total. - * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is - * a percentage (between 0 and 1), it can be omitted. - * @todo Consider having this event be a "fileprogress" event as well - * @constructor - */ - function ProgressEvent(loaded, total) { - this.Event_constructor("progress"); - - /** - * The amount that has been loaded (out of a total amount) - * @property loaded - * @type {Number} - */ - this.loaded = loaded; - - /** - * The total "size" of the load. - * @property total - * @type {Number} - * @default 1 - */ - this.total = (total == null) ? 1 : total; - - /** - * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`. - * @property progress - * @type {Number} - * @default 0 - */ - this.progress = (total == 0) ? 0 : this.loaded / this.total; - }; - - var p = createjs.extend(ProgressEvent, createjs.Event); - - /** - * Returns a clone of the ProgressEvent instance. - * @method clone - * @return {ProgressEvent} a clone of the Event instance. - **/ - p.clone = function() { - return new createjs.ProgressEvent(this.loaded, this.total); - }; - - createjs.ProgressEvent = createjs.promote(ProgressEvent, "Event"); - -}(window)); - -//############################################################################## -// LoadItem.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead, - * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A - * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the - * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}} - * @class LoadItem - * @constructor - * @since 0.6.0 - */ - function LoadItem() { - /** - * The source of the file that is being loaded. This property is required. The source can either be a - * string (recommended), or an HTML tag. - * This can also be an object, but in that case it has to include a type and be handled by a plugin. - * @property src - * @type {String} - * @default null - */ - this.src = null; - - /** - * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also - * be set manually. This is helpful in cases where a file does not have an extension. - * @property type - * @type {String} - * @default null - */ - this.type = null; - - /** - * A string identifier which can be used to reference the loaded object. If none is provided, this will be - * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}. - * @property id - * @type {String} - * @default null - */ - this.id = null; - - /** - * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest - * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has - * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this - * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in - * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`. - * @property maintainOrder - * @type {Boolean} - * @default false - */ - this.maintainOrder = false; - - /** - * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded. - * @property callback - * @type {String} - * @default null - */ - this.callback = null; - - /** - * An arbitrary data object, which is included with the loaded object. - * @property data - * @type {Object} - * @default null - */ - this.data = null; - - /** - * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or - * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as - * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @property method - * @type {String} - * @default get - */ - this.method = createjs.LoadItem.GET; - - /** - * An object hash of name/value pairs to send to the server. - * @property values - * @type {Object} - * @default null - */ - this.values = null; - - /** - * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default - * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the - * default headers by including them in your headers object. - * @property headers - * @type {Object} - * @default null - */ - this.headers = null; - - /** - * Enable credentials for XHR requests. - * @property withCredentials - * @type {Boolean} - * @default false - */ - this.withCredentials = false; - - /** - * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text - * based files (json, xml, text, css, js). - * @property mimeType - * @type {String} - * @default null - */ - this.mimeType = null; - - /** - * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain. - * @property crossOrigin - * @type {boolean} - * @default Anonymous - */ - this.crossOrigin = null; - - /** - * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property loadTimeout - * @type {Number} - * @default 8000 (8 seconds) - */ - this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - }; - - var p = LoadItem.prototype = {}; - var s = LoadItem; - - /** - * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR - * (level one) loading, as XHR (level 2) provides its own timeout event. - * @property LOAD_TIMEOUT_DEFAULT - * @type {number} - * @static - */ - s.LOAD_TIMEOUT_DEFAULT = 8000; - - /** - * Create a LoadItem. - *
      - *
    • String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
    • - *
    • LoadItem instances are returned as-is
    • - *
    • Objects are returned with any needed properties added
    • - *
    - * @method create - * @param {LoadItem|String|Object} value The load item value - * @returns {LoadItem|Object} - * @static - */ - s.create = function (value) { - if (typeof value == "string") { - var item = new LoadItem(); - item.src = value; - return item; - } else if (value instanceof s) { - return value; - } else if (value instanceof Object && value.src) { - if (value.loadTimeout == null) { - value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT; - } - return value; - } else { - throw new Error("Type not recognized."); - } - }; - - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

    Example

    - * - * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the LoadItem instance. - * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.) - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - createjs.LoadItem = s; - -}()); - -//############################################################################## -// RequestUtils.js -//############################################################################## - -(function () { - - /** - * Utilities that assist with parsing load items, and determining file types, etc. - * @class RequestUtils - */ - var s = {}; - - /** - * The Regular Expression used to test file URLS for an absolute path. - * @property ABSOLUTE_PATH - * @type {RegExp} - * @static - */ - s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i; - - /** - * The Regular Expression used to test file URLS for a relative path. - * @property RELATIVE_PATH - * @type {RegExp} - * @static - */ - s.RELATIVE_PATT = (/^[./]*?\//i); - - /** - * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string - * removed. - * @property EXTENSION_PATT - * @type {RegExp} - * @static - */ - s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i; - - /** - * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know: - *
      - *
    • If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or - * `//networkPath`)
    • - *
    • If the path is relative. Relative paths start with `../` or `/path` (or similar)
    • - *
    • The file extension. This is determined by the filename with an extension. Query strings are dropped, and - * the file path is expected to follow the format `name.ext`.
    • - *
    - * @method parseURI - * @param {String} path - * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension` - * property, which is the lowercase extension. - * @static - */ - s.parseURI = function (path) { - var info = {absolute: false, relative: false}; - if (path == null) { return info; } - - // Drop the query string - var queryIndex = path.indexOf("?"); - if (queryIndex > -1) { - path = path.substr(0, queryIndex); - } - - // Absolute - var match; - if (s.ABSOLUTE_PATT.test(path)) { - info.absolute = true; - - // Relative - } else if (s.RELATIVE_PATT.test(path)) { - info.relative = true; - } - - // Extension - if (match = path.match(s.EXTENSION_PATT)) { - info.extension = match[1].toLowerCase(); - } - return info; - }; - - /** - * Formats an object into a query string for either a POST or GET request. - * @method formatQueryString - * @param {Object} data The data to convert to a query string. - * @param {Array} [query] Existing name/value pairs to append on to this query. - * @static - */ - s.formatQueryString = function (data, query) { - if (data == null) { - throw new Error('You must specify data.'); - } - var params = []; - for (var n in data) { - params.push(n + '=' + escape(data[n])); - } - if (query) { - params = params.concat(query); - } - return params.join('&'); - }; - - /** - * A utility method that builds a file path using a source and a data object, and formats it into a new path. - * @method buildPath - * @param {String} src The source path to add values to. - * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the - * path will be preserved. - * @returns {string} A formatted string that contains the path and the supplied parameters. - * @static - */ - s.buildPath = function (src, data) { - if (data == null) { - return src; - } - - var query = []; - var idx = src.indexOf('?'); - - if (idx != -1) { - var q = src.slice(idx + 1); - query = query.concat(q.split('&')); - } - - if (idx != -1) { - return src.slice(0, idx) + '?' + this.formatQueryString(data, query); - } else { - return src + '?' + this.formatQueryString(data, query); - } - }; - - /** - * @method isCrossDomain - * @param {LoadItem|Object} item A load item with a `src` property. - * @return {Boolean} If the load item is loading from a different domain than the current location. - * @static - */ - s.isCrossDomain = function (item) { - var target = document.createElement("a"); - target.href = item.src; - - var host = document.createElement("a"); - host.href = location.href; - - var crossdomain = (target.hostname != "") && - (target.port != host.port || - target.protocol != host.protocol || - target.hostname != host.hostname); - return crossdomain; - }; - - /** - * @method isLocal - * @param {LoadItem|Object} item A load item with a `src` property - * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as - * well. - * @static - */ - s.isLocal = function (item) { - var target = document.createElement("a"); - target.href = item.src; - return target.hostname == "" && target.protocol == "file:"; - }; - - /** - * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked - * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play - * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get - * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on - * {{#crossLink "AbstractLoader"}}{{/crossLink}}. - * @method isBinary - * @param {String} type The item type. - * @return {Boolean} If the specified type is binary. - * @static - */ - s.isBinary = function (type) { - switch (type) { - case createjs.AbstractLoader.IMAGE: - case createjs.AbstractLoader.BINARY: - return true; - default: - return false; - } - }; - - /** - * Check if item is a valid HTMLImageElement - * @method isImageTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isImageTag = function(item) { - return item instanceof HTMLImageElement; - }; - - /** - * Check if item is a valid HTMLAudioElement - * @method isAudioTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isAudioTag = function(item) { - if (window.HTMLAudioElement) { - return item instanceof HTMLAudioElement; - } else { - return false; - } - }; - - /** - * Check if item is a valid HTMLVideoElement - * @method isVideoTag - * @param {Object} item - * @returns {Boolean} - * @static - */ - s.isVideoTag = function(item) { - if (window.HTMLVideoElement) { - return item instanceof HTMLVideoElement; - } else { - return false; - } - }; - - /** - * Determine if a specific type is a text-based asset, and should be loaded as UTF-8. - * @method isText - * @param {String} type The item type. - * @return {Boolean} If the specified type is text. - * @static - */ - s.isText = function (type) { - switch (type) { - case createjs.AbstractLoader.TEXT: - case createjs.AbstractLoader.JSON: - case createjs.AbstractLoader.MANIFEST: - case createjs.AbstractLoader.XML: - case createjs.AbstractLoader.CSS: - case createjs.AbstractLoader.SVG: - case createjs.AbstractLoader.JAVASCRIPT: - case createjs.AbstractLoader.SPRITESHEET: - return true; - default: - return false; - } - }; - - /** - * Determine the type of the object using common extensions. Note that the type can be passed in with the load item - * if it is an unusual extension. - * @method getTypeByExtension - * @param {String} extension The file extension to use to determine the load type. - * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if - * the type can not be determined by the extension. - * @static - */ - s.getTypeByExtension = function (extension) { - if (extension == null) { - return createjs.AbstractLoader.TEXT; - } - - switch (extension.toLowerCase()) { - case "jpeg": - case "jpg": - case "gif": - case "png": - case "webp": - case "bmp": - return createjs.AbstractLoader.IMAGE; - case "ogg": - case "mp3": - case "webm": - return createjs.AbstractLoader.SOUND; - case "mp4": - case "webm": - case "ts": - return createjs.AbstractLoader.VIDEO; - case "json": - return createjs.AbstractLoader.JSON; - case "xml": - return createjs.AbstractLoader.XML; - case "css": - return createjs.AbstractLoader.CSS; - case "js": - return createjs.AbstractLoader.JAVASCRIPT; - case 'svg': - return createjs.AbstractLoader.SVG; - default: - return createjs.AbstractLoader.TEXT; - } - }; - - createjs.RequestUtils = s; - -}()); - -//############################################################################## -// AbstractLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - -// constructor - /** - * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class, - * including the {{#crossLink "LoadQueue"}}{{/crossLink}}. - * @class AbstractLoader - * @param {LoadItem|object|string} loadItem The item to be loaded. - * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a - * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the - * other, so this is a suggested directive. - * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class, - * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc. - * @extends EventDispatcher - */ - function AbstractLoader(loadItem, preferXHR, type) { - this.EventDispatcher_constructor(); - - // public properties - /** - * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches - * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}. - * @property loaded - * @type {Boolean} - * @default false - */ - this.loaded = false; - - /** - * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property - * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}} - * instead. - * @property canceled - * @type {Boolean} - * @default false - * @readonly - */ - this.canceled = false; - - /** - * The current load progress (percentage) for this item. This will be a number between 0 and 1. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.loadFile("largeImage.png"); - * queue.on("progress", function() { - * console.log("Progress:", queue.progress, event.progress); - * }); - * - * @property progress - * @type {Number} - * @default 0 - */ - this.progress = 0; - - /** - * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of - * supported types. - * @property type - * @type {String} - */ - this.type = type; - - /** - * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader - * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property - * can be overridden to provide custom formatting. - * - * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be - * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks - * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is - * called in the current scope, as well as the success and error callbacks. - * - *

    Example asynchronous resultFormatter

    - * - * function _formatResult(loader) { - * return function(success, error) { - * if (errorCondition) { error(errorDetailEvent); } - * success(result); - * } - * } - * @property resultFormatter - * @type {Function} - * @default null - */ - this.resultFormatter = null; - - // protected properties - /** - * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}}, - * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}. - * @property _item - * @type {LoadItem|Object} - * @private - */ - if (loadItem) { - this._item = createjs.LoadItem.create(loadItem); - } else { - this._item = null; - } - - /** - * Whether the loader will try and load content using XHR (true) or HTML tags (false). - * @property _preferXHR - * @type {Boolean} - * @private - */ - this._preferXHR = preferXHR; - - /** - * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For - * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}. - * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method. - * @property _result - * @type {Object|String} - * @private - */ - this._result = null; - - /** - * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}} - * method, and passing `true`. - * @property _rawResult - * @type {Object|String} - * @private - */ - this._rawResult = null; - - /** - * A list of items that loaders load behind the scenes. This does not include the main item the loader is - * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and - * {{#crossLink "ManifestLoader"}}{{/crossLink}}. - * @property _loadItems - * @type {null} - * @protected - */ - this._loadedItems = null; - - /** - * The attribute the items loaded using tags use for the source. - * @type {string} - * @default null - * @private - */ - this._tagSrcAttribute = null; - - /** - * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc. - * @property _tag - * @type {Object} - * @private - */ - this._tag = null; - }; - - var p = createjs.extend(AbstractLoader, createjs.EventDispatcher); - var s = AbstractLoader; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - - /** - * Defines a POST request, use for a method value when loading data. - * @property POST - * @type {string} - * @default post - * @static - */ - s.POST = "POST"; - - /** - * Defines a GET request, use for a method value when loading data. - * @property GET - * @type {string} - * @default get - * @static - */ - s.GET = "GET"; - - /** - * The preload type for generic binary types. Note that images are loaded as binary files when using XHR. - * @property BINARY - * @type {String} - * @default binary - * @static - * @since 0.6.0 - */ - s.BINARY = "binary"; - - /** - * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a - * <style> tag when loaded with tags. - * @property CSS - * @type {String} - * @default css - * @static - * @since 0.6.0 - */ - s.CSS = "css"; - - /** - * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag. - * @property IMAGE - * @type {String} - * @default image - * @static - * @since 0.6.0 - */ - s.IMAGE = "image"; - - /** - * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a - * <script> tag. - * - * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into - * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier, - * only tag-loaded scripts are injected. - * @property JAVASCRIPT - * @type {String} - * @default javascript - * @static - * @since 0.6.0 - */ - s.JAVASCRIPT = "javascript"; - - /** - * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP, - * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON - * must contain a matching wrapper function. - * @property JSON - * @type {String} - * @default json - * @static - * @since 0.6.0 - */ - s.JSON = "json"; - - /** - * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a - * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON. - * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} - * property is set to. - * @property JSONP - * @type {String} - * @default jsonp - * @static - * @since 0.6.0 - */ - s.JSONP = "jsonp"; - - /** - * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded - * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an - * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} - * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead, - * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to. - * @property MANIFEST - * @type {String} - * @default manifest - * @static - * @since 0.6.0 - */ - s.MANIFEST = "manifest"; - - /** - * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an - * <audio> tag. - * @property SOUND - * @type {String} - * @default sound - * @static - * @since 0.6.0 - */ - s.SOUND = "sound"; - - /** - * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an - * <video> tag. - * @property VIDEO - * @type {String} - * @default video - * @static - * @since 0.6.0 - */ - s.VIDEO = "video"; - - /** - * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths. - * @property SPRITESHEET - * @type {String} - * @default spritesheet - * @static - * @since 0.6.0 - */ - s.SPRITESHEET = "spritesheet"; - - /** - * The preload type for SVG files. - * @property SVG - * @type {String} - * @default svg - * @static - * @since 0.6.0 - */ - s.SVG = "svg"; - - /** - * The preload type for text files, which is also the default file type if the type can not be determined. Text is - * loaded as raw text. - * @property TEXT - * @type {String} - * @default text - * @static - * @since 0.6.0 - */ - s.TEXT = "text"; - - /** - * The preload type for xml files. XML is loaded into an XML document. - * @property XML - * @type {String} - * @default xml - * @static - * @since 0.6.0 - */ - s.XML = "xml"; - -// Events - /** - * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to - * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event progress - * @since 0.3.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts. - * @event loadstart - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.1 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.3.0 - */ - - /** - * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was - * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was - * just a regular {{#crossLink "Event"}}{{/crossLink}}. - * @event error - * @since 0.3.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error. - * This enables loaders to maintain internal queues, and surface file load errors. - * @event fileerror - * @param {Object} target The object that dispatched the event. - * @param {String} type The even type ("fileerror") - * @param {LoadItem|object} The item that encountered the error - * @since 0.6.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables - * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s - * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a - * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("fileload") - * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the - * object will contain that value as a `src` property. - * @param {Object} result The HTML tag or parsed result of the loaded item. - * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted - * to a usable object. - * @since 0.6.0 - */ - - /** - * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load. - * This allows updates to the loader for specific loading needs, such as binary or XHR image loading. - * @event initialize - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type ("initialize") - * @param {AbstractLoader} loader The loader that has been initialized. - */ - - - /** - * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was - * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or - * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will - * be a {{#crossLink "LoadItem"}}{{/crossLink}}. - * @method getItem - * @return {Object} The manifest item that this loader is responsible for loading. - * @since 0.6.0 - */ - p.getItem = function () { - return this._item; - }; - - /** - * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}} - * event is dispatched. - * @method getResult - * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded - * data (if it exists). - * @return {Object} - * @since 0.6.0 - */ - p.getResult = function (raw) { - return raw ? this._rawResult : this._result; - }; - - /** - * Return the `tag` this object creates or uses for loading. - * @method getTag - * @return {Object} The tag instance - * @since 0.6.0 - */ - p.getTag = function () { - return this._tag; - }; - - /** - * Set the `tag` this item uses for loading. - * @method setTag - * @param {Object} tag The tag instance - * @since 0.6.0 - */ - p.setTag = function(tag) { - this._tag = tag; - }; - - /** - * Begin loading the item. This method is required when using a loader by itself. - * - *

    Example

    - * - * var queue = new createjs.LoadQueue(); - * queue.on("complete", handleComplete); - * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet - * queue.load(); - * - * @method load - */ - p.load = function () { - this._createRequest(); - - this._request.on("complete", this, this); - this._request.on("progress", this, this); - this._request.on("loadStart", this, this); - this._request.on("abort", this, this); - this._request.on("timeout", this, this); - this._request.on("error", this, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._request; - this.dispatchEvent(evt); - - this._request.load(); - }; - - /** - * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in - * the background), but events will not longer be dispatched. - * @method cancel - */ - p.cancel = function () { - this.canceled = true; - this.destroy(); - }; - - /** - * Clean up the loader. - * @method destroy - */ - p.destroy = function() { - if (this._request) { - this._request.removeAllEventListeners(); - this._request.destroy(); - } - - this._request = null; - - this._item = null; - this._rawResult = null; - this._result = null; - - this._loadItems = null; - - this.removeAllEventListeners(); - }; - - /** - * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} - * to expose items it loads internally. - * @method getLoadedItems - * @return {Array} A list of the items loaded by the loader. - * @since 0.6.0 - */ - p.getLoadedItems = function () { - return this._loadedItems; - }; - - - // Private methods - /** - * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or - * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}. - * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}}, - * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood. - * @method _createRequest - * @protected - */ - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); - } else { - this._request = new createjs.XHRRequest(this._item); - } - }; - - /** - * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented - * by loaders that require tag loading. - * @method _createTag - * @param {String} src The tag source - * @return {HTMLElement} The tag that was created - * @protected - */ - p._createTag = function(src) { return null; }; - - /** - * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendLoadStart - * @protected - */ - p._sendLoadStart = function () { - if (this._isCanceled()) { return; } - this.dispatchEvent("loadstart"); - }; - - /** - * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}. - * @method _sendProgress - * @param {Number | Object} value The progress of the loaded item, or an object containing loaded - * and total properties. - * @protected - */ - p._sendProgress = function (value) { - if (this._isCanceled()) { return; } - var event = null; - if (typeof(value) == "number") { - this.progress = value; - event = new createjs.ProgressEvent(this.progress); - } else { - event = value; - this.progress = value.loaded / value.total; - event.progress = this.progress; - if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; } - } - this.hasEventListener("progress") && this.dispatchEvent(event); - }; - - /** - * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event - * @method _sendComplete - * @protected - */ - p._sendComplete = function () { - if (this._isCanceled()) { return; } - - this.loaded = true; - - var event = new createjs.Event("complete"); - event.rawResult = this._rawResult; - - if (this._result != null) { - event.result = this._result; - } - - this.dispatchEvent(event); - }; - - /** - * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}} - * event for details on the event payload. - * @method _sendError - * @param {ErrorEvent} event The event object containing specific error properties. - * @protected - */ - p._sendError = function (event) { - if (this._isCanceled() || !this.hasEventListener("error")) { return; } - if (event == null) { - event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error - } - this.dispatchEvent(event); - }; - - /** - * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events - * do not cause issues after the queue has been cleaned up. - * @method _isCanceled - * @return {Boolean} If the loader has been canceled. - * @protected - */ - p._isCanceled = function () { - if (window.createjs == null || this.canceled) { - return true; - } - return false; - }; - - /** - * A custom result formatter function, which is called just before a request dispatches its complete event. Most - * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The - * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`. - * @property resultFormatter - * @type Function - * @return {Object} The formatted result - * @since 0.6.0 - */ - p.resultFormatter = null; - - /** - * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but - * this method can be overridden for custom behaviours. - * @method handleEvent - * @param {Event} event The event that the internal request dispatches. - * @protected - * @since 0.6.0 - */ - p.handleEvent = function (event) { - switch (event.type) { - case "complete": - this._rawResult = event.target._response; - var result = this.resultFormatter && this.resultFormatter(this); - if (result instanceof Function) { - result.call(this, - createjs.proxy(this._resultFormatSuccess, this), - createjs.proxy(this._resultFormatFailed, this) - ); - } else { - this._result = result || this._rawResult; - this._sendComplete(); - } - break; - case "progress": - this._sendProgress(event); - break; - case "error": - this._sendError(event); - break; - case "loadstart": - this._sendLoadStart(); - break; - case "abort": - case "timeout": - if (!this._isCanceled()) { - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR")); - } - break; - } - }; - - /** - * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} result The formatted result - * @private - */ - p._resultFormatSuccess = function (result) { - this._result = result; - this._sendComplete(); - }; - - /** - * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous - * functions. - * @method _resultFormatSuccess - * @param {Object} error The error event - * @private - */ - p._resultFormatFailed = function (event) { - this._sendError(event); - }; - - /** - * @method buildPath - * @protected - * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}} - * instead. - */ - p.buildPath = function (src, data) { - return createjs.RequestUtils.buildPath(src, data); - }; - - /** - * @method toString - * @return {String} a string representation of the instance. - */ - p.toString = function () { - return "[PreloadJS AbstractLoader]"; - }; - - createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher"); - -}()); - -//############################################################################## -// AbstractMediaLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that - * handle HTML media elements, such as Video and Audio. - * @class AbstractMediaLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @param {String} type The type of media to load. Usually "video" or "audio". - * @extends AbstractLoader - * @constructor - */ - function AbstractMediaLoader(loadItem, preferXHR, type) { - this.AbstractLoader_constructor(loadItem, preferXHR, type); - - // public properties - this.resultFormatter = this._formatResult; - - // protected properties - this._tagSrcAttribute = "src"; - - this.on("initialize", this._updateXHR, this); - }; - - var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader); - - // static properties - // public methods - p.load = function () { - // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here. - if (!this._tag) { - this._tag = this._createTag(this._item.src); - } - - this._tag.preload = "auto"; - this._tag.load(); - - this.AbstractLoader_load(); - }; - - // protected methods - /** - * Creates a new tag for loading if it doesn't exist yet. - * @method _createTag - * @private - */ - p._createTag = function () {}; - - - p._createRequest = function() { - if (!this._preferXHR) { - this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute); - } else { - this._request = new createjs.XHRRequest(this._item); - } - }; - - // protected methods - /** - * Before the item loads, set its mimeType and responseType. - * @property _updateXHR - * @param {Event} event - * @private - */ - p._updateXHR = function (event) { - // Only exists for XHR - if (event.loader.setResponseType) { - event.loader.setResponseType("blob"); - } - }; - - /** - * The result formatter for media files. - * @method _formatResult - * @param {AbstractLoader} loader - * @returns {HTMLVideoElement|HTMLAudioElement} - * @private - */ - p._formatResult = function (loader) { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.onstalled = null; - if (this._preferXHR) { - var URL = window.URL || window.webkitURL; - var result = loader.getResult(true); - - loader.getTag().src = URL.createObjectURL(result); - } - return loader.getTag(); - }; - - createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader"); - -}()); - -//############################################################################## -// AbstractRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}}, - * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the - * hood to get data. - * @class AbstractRequest - * @param {LoadItem} item - * @constructor - */ - var AbstractRequest = function (item) { - this._item = item; - }; - - var p = createjs.extend(AbstractRequest, createjs.EventDispatcher); - - // public methods - /** - * Begin a load. - * @method load - */ - p.load = function() {}; - - /** - * Clean up a request. - * @method destroy - */ - p.destroy = function() {}; - - /** - * Cancel an in-progress request. - * @method cancel - */ - p.cancel = function() {}; - - createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher"); - -}()); - -//############################################################################## -// TagRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts. - * @class TagRequest - * @param {LoadItem} loadItem - * @param {HTMLElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - */ - function TagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - /** - * The HTML tag instance that is used to load. - * @property _tag - * @type {HTMLElement} - * @protected - */ - this._tag = tag; - - /** - * The tag attribute that specifies the source, such as "src", "href", etc. - * @property _tagSrcAttribute - * @type {String} - * @protected - */ - this._tagSrcAttribute = srcAttribute; - - /** - * A method closure used for handling the tag load event. - * @property _loadedHandler - * @type {Function} - * @private - */ - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - - /** - * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after. - * @property _addedToDOM - * @type {Boolean} - * @private - */ - this._addedToDOM = false; - - /** - * Determines what the tags initial style.visibility was, so we can set it correctly after a load. - * - * @type {null} - * @private - */ - this._startTagVisibility = null; - }; - - var p = createjs.extend(TagRequest, createjs.AbstractRequest); - - // public methods - p.load = function () { - this._tag.onload = createjs.proxy(this._handleTagComplete, this); - this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this); - this._tag.onerror = createjs.proxy(this._handleError, this); - - var evt = new createjs.Event("initialize"); - evt.loader = this._tag; - - this.dispatchEvent(evt); - - this._hideTag(); - - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - - this._tag[this._tagSrcAttribute] = this._item.src; - - // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail. - if (this._tag.parentNode == null) { - window.document.body.appendChild(this._tag); - this._addedToDOM = true; - } - }; - - p.destroy = function() { - this._clean(); - this._tag = null; - - this.AbstractRequest_destroy(); - }; - - // private methods - /** - * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT - * and LINK tags), but other cases may exist. - * @method _handleReadyStateChange - * @private - */ - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - /** - * Handle any error events from the tag. - * @method _handleError - * @protected - */ - p._handleError = function() { - this._clean(); - this.dispatchEvent("error"); - }; - - /** - * Handle the tag's onload callback. - * @method _handleTagComplete - * @private - */ - p._handleTagComplete = function () { - this._rawResult = this._tag; - this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult; - - this._clean(); - this._showTag(); - - this.dispatchEvent("complete"); - }; - - /** - * The tag request has not loaded within the time specified in loadTimeout. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleTimeout = function () { - this._clean(); - this.dispatchEvent(new createjs.Event("timeout")); - }; - - /** - * Remove event listeners, but don't destroy the request object - * @method _clean - * @private - */ - p._clean = function() { - this._tag.onload = null; - this._tag.onreadystatechange = null; - this._tag.onerror = null; - if (this._addedToDOM && this._tag.parentNode != null) { - this._tag.parentNode.removeChild(this._tag); - } - clearTimeout(this._loadTimeout); - }; - - p._hideTag = function() { - this._startTagVisibility = this._tag.style.visibility; - this._tag.style.visibility = "hidden"; - }; - - p._showTag = function() { - this._tag.style.visibility = this._startTagVisibility; - }; - - /** - * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio - * that is already in a load, but not complete. - * @method _handleStalled - * @private - */ - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// MediaTagRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio. - * @class MediaTagRequest - * @param {LoadItem} loadItem - * @param {HTMLAudioElement|HTMLVideoElement} tag - * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc. - * @constructor - */ - function MediaTagRequest(loadItem, tag, srcAttribute) { - this.AbstractRequest_constructor(loadItem); - - // protected properties - this._tag = tag; - this._tagSrcAttribute = srcAttribute; - this._loadedHandler = createjs.proxy(this._handleTagComplete, this); - }; - - var p = createjs.extend(MediaTagRequest, createjs.TagRequest); - var s = MediaTagRequest; - - // public methods - p.load = function () { - var sc = createjs.proxy(this._handleStalled, this); - this._stalledCallback = sc; - - var pc = createjs.proxy(this._handleProgress, this); - this._handleProgress = pc; - - this._tag.addEventListener("stalled", sc); - this._tag.addEventListener("progress", pc); - - // This will tell us when audio is buffered enough to play through, but not when its loaded. - // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient. - this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event. - - this.TagRequest_load(); - }; - - // private methods - p._handleReadyStateChange = function () { - clearTimeout(this._loadTimeout); - // This is strictly for tags in browsers that do not support onload. - var tag = this._tag; - - // Complete is for old IE support. - if (tag.readyState == "loaded" || tag.readyState == "complete") { - this._handleTagComplete(); - } - }; - - p._handleStalled = function () { - //Ignore, let the timeout take care of it. Sometimes its not really stopped. - }; - - /** - * An XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - // protected methods - p._clean = function () { - this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler); - this._tag.removeEventListener("stalled", this._stalledCallback); - this._tag.removeEventListener("progress", this._progressCallback); - - this.TagRequest__clean(); - }; - - createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest"); - -}()); - -//############################################################################## -// XHRRequest.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - -// constructor - /** - * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used - * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary. - * XHR requests load the content as text or binary data, provide progress and consistent completion events, and - * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for - * cross-domain loading. - * @class XHRRequest - * @constructor - * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} - * for an overview of supported file properties. - * @extends AbstractLoader - */ - function XHRRequest (item) { - this.AbstractRequest_constructor(item); - - // protected properties - /** - * A reference to the XHR request used to load the content. - * @property _request - * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP} - * @private - */ - this._request = null; - - /** - * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1, - * typically IE9). - * @property _loadTimeout - * @type {Number} - * @private - */ - this._loadTimeout = null; - - /** - * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect - * the version, so we use capabilities to make a best guess. - * @property _xhrLevel - * @type {Number} - * @default 1 - * @private - */ - this._xhrLevel = 1; - - /** - * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be - * null until the file is loaded. - * @property _response - * @type {mixed} - * @private - */ - this._response = null; - - /** - * The response of the loaded file before it is modified. In most cases, content is converted from raw text to - * an HTML tag or a formatted object which is set to the result property, but the developer may still - * want to access the raw content as it was loaded. - * @property _rawResponse - * @type {String|Object} - * @private - */ - this._rawResponse = null; - - this._canceled = false; - - // Setup our event handlers now. - this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this); - this._handleProgressProxy = createjs.proxy(this._handleProgress, this); - this._handleAbortProxy = createjs.proxy(this._handleAbort, this); - this._handleErrorProxy = createjs.proxy(this._handleError, this); - this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this); - this._handleLoadProxy = createjs.proxy(this._handleLoad, this); - this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this); - - if (!this._createXHR(item)) { - //TODO: Throw error? - } - }; - - var p = createjs.extend(XHRRequest, createjs.AbstractRequest); - -// static properties - /** - * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE. - * @property ACTIVEX_VERSIONS - * @type {Array} - * @since 0.4.2 - * @private - */ - XHRRequest.ACTIVEX_VERSIONS = [ - "Msxml2.XMLHTTP.6.0", - "Msxml2.XMLHTTP.5.0", - "Msxml2.XMLHTTP.4.0", - "MSXML2.XMLHTTP.3.0", - "MSXML2.XMLHTTP", - "Microsoft.XMLHTTP" - ]; - -// Public methods - /** - * Look up the loaded result. - * @method getResult - * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content - * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be - * returned instead. - * @return {Object} A result object containing the content that was loaded, such as: - *
      - *
    • An image tag (<image />) for images
    • - *
    • A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the - * HTML head.
    • - *
    • A style tag for CSS (<style />)
    • - *
    • Raw text for TEXT
    • - *
    • A formatted JavaScript object defined by JSON
    • - *
    • An XML document
    • - *
    • An binary arraybuffer loaded by XHR
    • - *
    - * Note that if a raw result is requested, but not found, the result will be returned instead. - */ - p.getResult = function (raw) { - if (raw && this._rawResponse) { - return this._rawResponse; - } - return this._response; - }; - - // Overrides abstract method in AbstractRequest - p.cancel = function () { - this.canceled = true; - this._clean(); - this._request.abort(); - }; - - // Overrides abstract method in AbstractLoader - p.load = function () { - if (this._request == null) { - this._handleError(); - return; - } - - //Events - if (this._request.addEventListener != null) { - this._request.addEventListener("loadstart", this._handleLoadStartProxy, false); - this._request.addEventListener("progress", this._handleProgressProxy, false); - this._request.addEventListener("abort", this._handleAbortProxy, false); - this._request.addEventListener("error", this._handleErrorProxy, false); - this._request.addEventListener("timeout", this._handleTimeoutProxy, false); - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.addEventListener("load", this._handleLoadProxy, false); - this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false); - } else { - // IE9 support - this._request.onloadstart = this._handleLoadStartProxy; - this._request.onprogress = this._handleProgressProxy; - this._request.onabort = this._handleAbortProxy; - this._request.onerror = this._handleErrorProxy; - this._request.ontimeout = this._handleTimeoutProxy; - - // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these. - this._request.onload = this._handleLoadProxy; - this._request.onreadystatechange = this._handleReadyStateChangeProxy; - } - - // Set up a timeout if we don't have XHR2 - if (this._xhrLevel == 1) { - this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout); - } - - // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome - try { - if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) { - this._request.send(); - } else if (this._item.method == createjs.AbstractLoader.POST) { - this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)); - } - } catch (error) { - this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error)); - } - }; - - p.setResponseType = function (type) { - // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded - if (type === 'blob') { - type = window.URL ? 'blob' : 'arraybuffer'; - this._responseType = type; - } - this._request.responseType = type; - }; - - /** - * Get all the response headers from the XmlHttpRequest. - * - * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match - * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair, - * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE - * pair. - * @method getAllResponseHeaders - * @return {String} - * @since 0.4.1 - */ - p.getAllResponseHeaders = function () { - if (this._request.getAllResponseHeaders instanceof Function) { - return this._request.getAllResponseHeaders(); - } else { - return null; - } - }; - - /** - * Get a specific response header from the XmlHttpRequest. - * - * From the docs: Returns the header field value from the response of which the field name matches - * header, unless the field name is Set-Cookie or Set-Cookie2. - * @method getResponseHeader - * @param {String} header The header name to retrieve. - * @return {String} - * @since 0.4.1 - */ - p.getResponseHeader = function (header) { - if (this._request.getResponseHeader instanceof Function) { - return this._request.getResponseHeader(header); - } else { - return null; - } - }; - -// protected methods - /** - * The XHR request has reported progress. - * @method _handleProgress - * @param {Object} event The XHR progress event. - * @private - */ - p._handleProgress = function (event) { - if (!event || event.loaded > 0 && event.total == 0) { - return; // Sometimes we get no "total", so just ignore the progress event. - } - - var newEvent = new createjs.ProgressEvent(event.loaded, event.total); - this.dispatchEvent(newEvent); - }; - - /** - * The XHR request has reported a load start. - * @method _handleLoadStart - * @param {Object} event The XHR loadStart event. - * @private - */ - p._handleLoadStart = function (event) { - clearTimeout(this._loadTimeout); - this.dispatchEvent("loadstart"); - }; - - /** - * The XHR request has reported an abort event. - * @method handleAbort - * @param {Object} event The XHR abort event. - * @private - */ - p._handleAbort = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event)); - }; - - /** - * The XHR request has reported an error event. - * @method _handleError - * @param {Object} event The XHR error event. - * @private - */ - p._handleError = function (event) { - this._clean(); - this.dispatchEvent(new createjs.ErrorEvent(event.message)); - }; - - /** - * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload - * event, so we must monitor the readyStateChange to determine if the file is loaded. - * @method _handleReadyStateChange - * @param {Object} event The XHR readyStateChange event. - * @private - */ - p._handleReadyStateChange = function (event) { - if (this._request.readyState == 4) { - this._handleLoad(); - } - }; - - /** - * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has - * request.readyState == 4. Only the first call to this method will be processed. - * @method _handleLoad - * @param {Object} event The XHR load event. - * @private - */ - p._handleLoad = function (event) { - if (this.loaded) { - return; - } - this.loaded = true; - - var error = this._checkError(); - if (error) { - this._handleError(error); - return; - } - - this._response = this._getResponse(); - // Convert arraybuffer back to blob - if (this._responseType === 'arraybuffer') { - try { - this._response = new Blob([this._response]); - } catch (e) { - // Fallback to use BlobBuilder if Blob constructor is not supported - // Tested on Android 2.3 ~ 4.2 and iOS5 safari - window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - if (e.name === 'TypeError' && window.BlobBuilder) { - var builder = new BlobBuilder(); - builder.append(this._response); - this._response = builder.getBlob(); - } - } - } - this._clean(); - - this.dispatchEvent(new createjs.Event("complete")); - }; - - /** - * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout - * callback. - * @method _handleTimeout - * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout. - * @private - */ - p._handleTimeout = function (event) { - this._clean(); - - this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event)); - }; - -// Protected - /** - * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note - * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code. - * @method _checkError - * @return {int} If the request status returns an error code. - * @private - */ - p._checkError = function () { - //LM: Probably need additional handlers here, maybe 501 - var status = parseInt(this._request.status); - - switch (status) { - case 404: // Not Found - case 0: // Not Loaded - return new Error(status); - } - return null; - }; - - /** - * Validate the response. Different browsers have different approaches, some of which throw errors when accessed - * in other browsers. If there is no response, the _response property will remain null. - * @method _getResponse - * @private - */ - p._getResponse = function () { - if (this._response != null) { - return this._response; - } - - if (this._request.response != null) { - return this._request.response; - } - - // Android 2.2 uses .responseText - try { - if (this._request.responseText != null) { - return this._request.responseText; - } - } catch (e) { - } - - // When loading XML, IE9 does not return .response, instead it returns responseXML.xml - try { - if (this._request.responseXML != null) { - return this._request.responseXML; - } - } catch (e) { - } - - return null; - }; - - /** - * Create an XHR request. Depending on a number of factors, we get totally different results. - *
    1. Some browsers get an XDomainRequest when loading cross-domain.
    2. - *
    3. XMLHttpRequest are created when available.
    4. - *
    5. ActiveX.XMLHTTP objects are used in older IE browsers.
    6. - *
    7. Text requests override the mime type if possible
    8. - *
    9. Origin headers are sent for crossdomain requests in some browsers.
    10. - *
    11. Binary loads set the response type to "arraybuffer"
    - * @method _createXHR - * @param {Object} item The requested item that is being loaded. - * @return {Boolean} If an XHR request or equivalent was successfully created. - * @private - */ - p._createXHR = function (item) { - // Check for cross-domain loads. We can't fully support them, but we can try. - var crossdomain = createjs.RequestUtils.isCrossDomain(item); - var headers = {}; - - // Create the request. Fallback to whatever support we have. - var req = null; - if (window.XMLHttpRequest) { - req = new XMLHttpRequest(); - // This is 8 or 9, so use XDomainRequest instead. - if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) { - req = new XDomainRequest(); - } - } else { // Old IE versions use a different approach - for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) { - var axVersion = s.ACTIVEX_VERSIONS[i]; - try { - req = new ActiveXObject(axVersion); - break; - } catch (e) { - } - } - if (req == null) { - return false; - } - } - - // Default to utf-8 for Text requests. - if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) { - item.mimeType = "text/plain; charset=utf-8"; - } - - // IE9 doesn't support overrideMimeType(), so we need to check for it. - if (item.mimeType && req.overrideMimeType) { - req.overrideMimeType(item.mimeType); - } - - // Determine the XHR level - this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1; - - var src = null; - if (item.method == createjs.AbstractLoader.GET) { - src = createjs.RequestUtils.buildPath(item.src, item.values); - } else { - src = item.src; - } - - // Open the request. Set cross-domain flags if it is supported (XHR level 1 only) - req.open(item.method || createjs.AbstractLoader.GET, src, true); - - if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) { - headers["Origin"] = location.origin; - } - - // To send data we need to set the Content-type header) - if (item.values && item.method == createjs.AbstractLoader.POST) { - headers["Content-Type"] = "application/x-www-form-urlencoded"; - } - - if (!crossdomain && !headers["X-Requested-With"]) { - headers["X-Requested-With"] = "XMLHttpRequest"; - } - - if (item.headers) { - for (var n in item.headers) { - headers[n] = item.headers[n]; - } - } - - for (n in headers) { - req.setRequestHeader(n, headers[n]) - } - - if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) { - req.withCredentials = item.withCredentials; - } - - this._request = req; - - return true; - }; - - /** - * A request has completed (or failed or canceled), and needs to be disposed. - * @method _clean - * @private - */ - p._clean = function () { - clearTimeout(this._loadTimeout); - - if (this._request.removeEventListener != null) { - this._request.removeEventListener("loadstart", this._handleLoadStartProxy); - this._request.removeEventListener("progress", this._handleProgressProxy); - this._request.removeEventListener("abort", this._handleAbortProxy); - this._request.removeEventListener("error", this._handleErrorProxy); - this._request.removeEventListener("timeout", this._handleTimeoutProxy); - this._request.removeEventListener("load", this._handleLoadProxy); - this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy); - } else { - this._request.onloadstart = null; - this._request.onprogress = null; - this._request.onabort = null; - this._request.onerror = null; - this._request.ontimeout = null; - this._request.onload = null; - this._request.onreadystatechange = null; - } - }; - - p.toString = function () { - return "[PreloadJS XHRRequest]"; - }; - - createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest"); - -}()); - -//############################################################################## -// SoundLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - // constructor - /** - * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which - * should be created by either a library playing the sound (such as SoundJS, or an - * external framework that handles audio playback. To load content that can be played by WebAudio, use the - * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually. - * @class SoundLoader - * @param {LoadItem|Object} loadItem - * @param {Boolean} preferXHR - * @extends AbstractMediaLoader - * @constructor - */ - function SoundLoader(loadItem, preferXHR) { - this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND); - - // protected properties - if (createjs.RequestUtils.isAudioTag(loadItem)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) { - this._tag = loadItem; - } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) { - this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src; - } - - if (this._tag != null) { - this._preferXHR = false; - } - }; - - var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader); - var s = SoundLoader; - - // static methods - /** - * Determines if the loader can load a specific item. This loader can only load items that are of type - * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}. - * @method canLoadItem - * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load. - * @returns {Boolean} Whether the loader can load the item. - * @static - */ - s.canLoadItem = function (item) { - return item.type == createjs.AbstractLoader.SOUND; - }; - - // protected methods - p._createTag = function (src) { - var tag = document.createElement("audio"); - tag.autoplay = false; - tag.preload = "none"; - - //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works. - tag.src = src; - return tag; - }; - - createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader"); - -}()); - -//############################################################################## -// AudioSprite.js -//############################################################################## - -// NOTE this is "Class" is purely to document audioSprite Setup and usage. - - -/** - * Note: AudioSprite is not a class, but its usage is easily lost in the documentation, so it has been called - * out here for quick reference. - * - * Audio sprites are much like CSS sprites or image sprite sheets: multiple audio assets grouped into a single file. - * Audio sprites work around limitations in certain browsers, where only a single sound can be loaded and played at a - * time. We recommend at least 300ms of silence between audio clips to deal with HTML audio tag inaccuracy, and to prevent - * accidentally playing bits of the neighbouring clips. - * - * Benefits of Audio Sprites: - *
      - *
    • More robust support for older browsers and devices that only allow a single audio instance, such as iOS 5.
    • - *
    • They provide a work around for the Internet Explorer 9 audio tag limit, which restricts how many different - * sounds that could be loaded at once.
    • - *
    • Faster loading by only requiring a single network request for several sounds, especially on mobile devices - * where the network round trip for each file can add significant latency.
    • - *
    - * - * Drawbacks of Audio Sprites - *
      - *
    • No guarantee of smooth looping when using HTML or Flash audio. If you have a track that needs to loop - * smoothly and you are supporting non-web audio browsers, do not use audio sprites for that sound if you can avoid - * it.
    • - *
    • No guarantee that HTML audio will play back immediately, especially the first time. In some browsers - * (Chrome!), HTML audio will only load enough to play through at the current download speed – so we rely on the - * `canplaythrough` event to determine if the audio is loaded. Since audio sprites must jump ahead to play specific - * sounds, the audio may not yet have downloaded fully.
    • - *
    • Audio sprites share the same core source, so if you have a sprite with 5 sounds and are limited to 2 - * concurrently playing instances, you can only play 2 of the sounds at the same time.
    • - *
    - * - *

    Example

    - * - * createjs.Sound.initializeDefaultPlugins(); - * var assetsPath = "./assets/"; - * var sounds = [{ - * src:"MyAudioSprite.ogg", data: { - * audioSprite: [ - * {id:"sound1", startTime:0, duration:500}, - * {id:"sound2", startTime:1000, duration:400}, - * {id:"sound3", startTime:1700, duration: 1000} - * ]} - * } - * ]; - * createjs.Sound.alternateExtensions = ["mp3"]; - * createjs.Sound.on("fileload", loadSound); - * createjs.Sound.registerSounds(sounds, assetsPath); - * // after load is complete - * createjs.Sound.play("sound2"); - * - * You can also create audio sprites on the fly by setting the startTime and duration when creating an new AbstractSoundInstance. - * - * createjs.Sound.play("MyAudioSprite", {startTime: 1000, duration: 400}); - * - * The excellent CreateJS community has created a tool to create audio sprites, available at - * https://github.com/tonistiigi/audiosprite, - * as well as a jsfiddle to convert the output - * to SoundJS format. - * - * @class AudioSprite - * @since 0.6.0 - */ - -//############################################################################## -// PlayPropsConfig.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - /** - * A class to store the optional play properties passed in {{#crossLink "Sound/play"}}{{/crossLink}} and - * {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} calls. - * - * Optional Play Properties Include: - *
      - *
    • interrupt - How to interrupt any currently playing instances of audio with the same source, - * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE - * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
    • - *
    • delay - The amount of time to delay the start of audio playback, in milliseconds.
    • - *
    • offset - The offset from the start of the audio to begin playback, in milliseconds.
    • - *
    • loop - How many times the audio loops when it reaches the end of playback. The default is 0 (no - * loops), and -1 can be used for infinite playback.
    • - *
    • volume - The volume of the sound, between 0 and 1. Note that the master volume is applied - * against the individual volume.
    • - *
    • pan - The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
    • - *
    • startTime - To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
    • - *
    • duration - To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
    • - *
    - * - *

    Example

    - * - * var ppc = new createjs.PlayPropsConfig().set({interrupt: createjs.Sound.INTERRUPT_ANY, loop: -1, volume: 0.5}) - * createjs.Sound.play("mySound", ppc); - * mySoundInstance.play(ppc); - * - * @class PlayPropsConfig - * @constructor - * @since 0.6.1 - */ - // TODO think of a better name for this class - var PlayPropsConfig = function () { -// Public Properties - /** - * How to interrupt any currently playing instances of audio with the same source, - * if the maximum number of instances of the sound are already playing. Values are defined as - * INTERRUPT_TYPE constants on the Sound class, with the default defined by - * {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}. - * @property interrupt - * @type {string} - * @default null - */ - this.interrupt = null; - - /** - * The amount of time to delay the start of audio playback, in milliseconds. - * @property delay - * @type {Number} - * @default null - */ - this.delay = null; - - /** - * The offset from the start of the audio to begin playback, in milliseconds. - * @property offset - * @type {number} - * @default null - */ - this.offset = null; - - /** - * How many times the audio loops when it reaches the end of playback. The default is 0 (no - * loops), and -1 can be used for infinite playback. - * @property loop - * @type {number} - * @default null - */ - this.loop = null; - - /** - * The volume of the sound, between 0 and 1. Note that the master volume is applied - * against the individual volume. - * @property volume - * @type {number} - * @default null - */ - this.volume = null; - - /** - * The left-right pan of the sound (if supported), between -1 (left) and 1 (right). - * @property pan - * @type {number} - * @default null - */ - this.pan = null; - - /** - * Used to create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds. - * @property startTime - * @type {number} - * @default null - */ - this.startTime = null; - - /** - * Used to create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds. - * @property duration - * @type {number} - * @default null - */ - this.duration = null; - }; - var p = PlayPropsConfig.prototype = {}; - var s = PlayPropsConfig; - - -// Static Methods - /** - * Creates a PlayPropsConfig from another PlayPropsConfig or an Object. - * - * @method create - * @param {PlayPropsConfig|Object} value The play properties - * @returns {PlayPropsConfig} - * @static - */ - s.create = function (value) { - if (value instanceof s || value instanceof Object) { - var ppc = new createjs.PlayPropsConfig(); - ppc.set(value); - return ppc; - } else { - throw new Error("Type not recognized."); - } - }; - -// Public Methods - /** - * Provides a chainable shortcut method for setting a number of properties on the instance. - * - *

    Example

    - * - * var PlayPropsConfig = new createjs.PlayPropsConfig().set({loop:-1, volume:0.7}); - * - * @method set - * @param {Object} props A generic object containing properties to copy to the PlayPropsConfig instance. - * @return {PlayPropsConfig} Returns the instance the method is called on (useful for chaining calls.) - */ - p.set = function(props) { - for (var n in props) { this[n] = props[n]; } - return this; - }; - - p.toString = function() { - return "[PlayPropsConfig]"; - }; - - createjs.PlayPropsConfig = s; - -}()); - -//############################################################################## -// Sound.js -//############################################################################## - -this.createjs = this.createjs || {}; - - - -(function () { - "use strict"; - - /** - * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins. - * All Sound APIs on this class are static. - * - * Registering and Preloading
    - * Before you can play a sound, it must be registered. You can do this with {{#crossLink "Sound/registerSound"}}{{/crossLink}}, - * or register multiple sounds using {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. If you don't register a - * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}}, - * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use - * PreloadJS, registration is handled for you when the sound is - * preloaded. It is recommended to preload sounds either internally using the register functions or externally using - * PreloadJS so they are ready when you want to use them. - * - * Playback
    - * To play a sound once it's been registered and preloaded, use the {{#crossLink "Sound/play"}}{{/crossLink}} method. - * This method returns a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} which can be paused, resumed, muted, etc. - * Please see the {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} documentation for more on the instance control APIs. - * - * Plugins
    - * By default, the {{#crossLink "WebAudioPlugin"}}{{/crossLink}} or the {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}} - * are used (when available), although developers can change plugin priority or add new plugins (such as the - * provided {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}). Please see the {{#crossLink "Sound"}}{{/crossLink}} API - * methods for more on the playback and plugin APIs. To install plugins, or specify a different plugin order, see - * {{#crossLink "Sound/installPlugins"}}{{/crossLink}}. - * - *

    Example

    - * - * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio"; - * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.FlashAudioPlugin]); - * createjs.Sound.alternateExtensions = ["mp3"]; - * createjs.Sound.on("fileload", this.loadHandler, this); - * createjs.Sound.registerSound("path/to/mySound.ogg", "sound"); - * function loadHandler(event) { - * // This is fired for each sound that is registered. - * var instance = createjs.Sound.play("sound"); // play using id. Could also use full source path or event.src. - * instance.on("complete", this.handleComplete, this); - * instance.volume = 0.5; - * } - * - * The maximum number of concurrently playing instances of the same sound can be specified in the "data" argument - * of {{#crossLink "Sound/registerSound"}}{{/crossLink}}. Note that if not specified, the active plugin will apply - * a default limit. Currently HTMLAudioPlugin sets a default limit of 2, while WebAudioPlugin and FlashAudioPlugin set a - * default limit of 100. - * - * createjs.Sound.registerSound("sound.mp3", "soundId", 4); - * - * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is - * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal - * load. As a result, it may fail to play the first time play is called if the audio is not finished loading. Use - * the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} event to determine when a sound has finished internally - * preloading. It is recommended that all audio is preloaded before it is played. - * - * var queue = new createjs.LoadQueue(); - * queue.installPlugin(createjs.Sound); - * - * Audio Sprites
    - * SoundJS has added support for {{#crossLink "AudioSprite"}}{{/crossLink}}, available as of version 0.6.0. - * For those unfamiliar with audio sprites, they are much like CSS sprites or sprite sheets: multiple audio assets - * grouped into a single file. - * - *

    Example

    - * - * var assetsPath = "./assets/"; - * var sounds = [{ - * src:"MyAudioSprite.ogg", data: { - * audioSprite: [ - * {id:"sound1", startTime:0, duration:500}, - * {id:"sound2", startTime:1000, duration:400}, - * {id:"sound3", startTime:1700, duration: 1000} - * ]} - * } - * ]; - * createjs.Sound.alternateExtensions = ["mp3"]; - * createjs.Sound.on("fileload", loadSound); - * createjs.Sound.registerSounds(sounds, assetsPath); - * // after load is complete - * createjs.Sound.play("sound2"); - * - * Mobile Playback
    - * Devices running iOS require the WebAudio context to be "unlocked" by playing at least one sound inside of a user- - * initiated event (such as touch/click). Earlier versions of SoundJS included a "MobileSafe" sample, but this is no - * longer necessary as of SoundJS 0.6.2. - *
      - *
    • - * In SoundJS 0.4.1 and above, you can either initialize plugins or use the {{#crossLink "WebAudioPlugin/playEmptySound"}}{{/crossLink}} - * method in the call stack of a user input event to manually unlock the audio context. - *
    • - *
    • - * In SoundJS 0.6.2 and above, SoundJS will automatically listen for the first document-level "mousedown" - * and "touchend" event, and unlock WebAudio. This will continue to check these events until the WebAudio - * context becomes "unlocked" (changes from "suspended" to "running") - *
    • - *
    • - * Both the "mousedown" and "touchend" events can be used to unlock audio in iOS9+, the "touchstart" event - * will work in iOS8 and below. The "touchend" event will only work in iOS9 when the gesture is interpreted - * as a "click", so if the user long-presses the button, it will no longer work. - *
    • - *
    • - * When using the EaselJS Touch class, - * the "mousedown" event will not fire when a canvas is clicked, since MouseEvents are prevented, to ensure - * only touch events fire. To get around this, you can either rely on "touchend", or: - *
        - *
      1. Set the `allowDefault` property on the Touch class constructor to `true` (defaults to `false`).
      2. - *
      3. Set the `preventSelection` property on the EaselJS `Stage` to `false`.
      4. - *
      - * These settings may change how your application behaves, and are not recommended. - *
    • - *
    - * - * Loading Alternate Paths and Extension-less Files
    - * SoundJS supports loading alternate paths and extension-less files by passing an object instead of a string for - * the `src` property, which is a hash using the format `{extension:"path", extension2:"path2"}`. These labels are - * how SoundJS determines if the browser will support the sound. This also enables multiple formats to live in - * different folders, or on CDNs, which often has completely different filenames for each file. - * - * Priority is determined by the property order (first property is tried first). This is supported by both internal loading - * and loading with PreloadJS. - * - * Note: an id is required for playback. - * - *

    Example

    - * - * var sounds = {path:"./audioPath/", - * manifest: [ - * {id: "cool", src: {mp3:"mp3/awesome.mp3", ogg:"noExtensionOggFile"}} - * ]}; - * - * createjs.Sound.alternateExtensions = ["mp3"]; - * createjs.Sound.addEventListener("fileload", handleLoad); - * createjs.Sound.registerSounds(sounds); - * - *

    Known Browser and OS issues

    - * IE 9 HTML Audio limitations
    - *
    • There is a delay in applying volume changes to tags that occurs once playback is started. So if you have - * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of - * when or how you apply the volume change, as the tag seems to need to play to apply it.
    • - *
    • MP3 encoding will not always work for audio tags, particularly in Internet Explorer. We've found default - * encoding with 64kbps works.
    • - *
    • Occasionally very short samples will get cut off.
    • - *
    • There is a limit to how many audio tags you can load and play at once, which appears to be determined by - * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe - * estimate.
    - * - * Firefox 25 Web Audio limitations - *
    • mp3 audio files do not load properly on all windows machines, reported - * here.
      - * For this reason it is recommended to pass another FF supported type (ie ogg) first until this bug is resolved, if - * possible.
    - - * Safari limitations
    - *
    • Safari requires Quicktime to be installed for audio playback.
    - * - * iOS 6 Web Audio limitations
    - *
    • Sound is initially locked, and must be unlocked via a user-initiated event. Please see the section on - * Mobile Playback above.
    • - *
    • A bug exists that will distort un-cached web audio when a video element is present in the DOM that has audio - * at a different sampleRate.
    • - *
    - * - * Android HTML Audio limitations
    - *
    • We have no control over audio volume. Only the user can set volume on their device.
    • - *
    • We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use - * a delay.
    - * - * Web Audio and PreloadJS
    - *
    • Web Audio must be loaded through XHR, therefore when used with PreloadJS, tag loading is not possible. - * This means that tag loading can not be used to avoid cross domain issues.
      • - * - * @class Sound - * @static - * @uses EventDispatcher - */ - function Sound() { - throw "Sound cannot be instantiated"; - } - - var s = Sound; - - -// Static Properties - /** - * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of - * instances of the sound are already playing. - * @property INTERRUPT_ANY - * @type {String} - * @default any - * @static - */ - s.INTERRUPT_ANY = "any"; - - /** - * The interrupt value to interrupt the earliest currently playing instance with the same source that progressed the - * least distance in the audio track, if the maximum number of instances of the sound are already playing. - * @property INTERRUPT_EARLY - * @type {String} - * @default early - * @static - */ - s.INTERRUPT_EARLY = "early"; - - /** - * The interrupt value to interrupt the currently playing instance with the same source that progressed the most - * distance in the audio track, if the maximum number of instances of the sound are already playing. - * @property INTERRUPT_LATE - * @type {String} - * @default late - * @static - */ - s.INTERRUPT_LATE = "late"; - - /** - * The interrupt value to not interrupt any currently playing instances with the same source, if the maximum number of - * instances of the sound are already playing. - * @property INTERRUPT_NONE - * @type {String} - * @default none - * @static - */ - s.INTERRUPT_NONE = "none"; - - /** - * Defines the playState of an instance that is still initializing. - * @property PLAY_INITED - * @type {String} - * @default playInited - * @static - */ - s.PLAY_INITED = "playInited"; - - /** - * Defines the playState of an instance that is currently playing or paused. - * @property PLAY_SUCCEEDED - * @type {String} - * @default playSucceeded - * @static - */ - s.PLAY_SUCCEEDED = "playSucceeded"; - - /** - * Defines the playState of an instance that was interrupted by another instance. - * @property PLAY_INTERRUPTED - * @type {String} - * @default playInterrupted - * @static - */ - s.PLAY_INTERRUPTED = "playInterrupted"; - - /** - * Defines the playState of an instance that completed playback. - * @property PLAY_FINISHED - * @type {String} - * @default playFinished - * @static - */ - s.PLAY_FINISHED = "playFinished"; - - /** - * Defines the playState of an instance that failed to play. This is usually caused by a lack of available channels - * when the interrupt mode was "INTERRUPT_NONE", the playback stalled, or the sound could not be found. - * @property PLAY_FAILED - * @type {String} - * @default playFailed - * @static - */ - s.PLAY_FAILED = "playFailed"; - - /** - * A list of the default supported extensions that Sound will try to play. Plugins will check if the browser - * can play these types, so modifying this list before a plugin is initialized will allow the plugins to try to - * support additional media types. - * - * NOTE this does not currently work for {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}. - * - * More details on file formats can be found at http://en.wikipedia.org/wiki/Audio_file_format.
        - * A very detailed list of file formats can be found at http://www.fileinfo.com/filetypes/audio. - * @property SUPPORTED_EXTENSIONS - * @type {Array[String]} - * @default ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"] - * @since 0.4.0 - * @static - */ - s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; - - /** - * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map - * that support so plugins can accurately determine if an extension is supported. Adding to this list can help - * plugins determine more accurately if an extension is supported. - * - * A useful list of extensions for each format can be found at http://html5doctor.com/html5-audio-the-state-of-play/. - * @property EXTENSION_MAP - * @type {Object} - * @since 0.4.0 - * @default {m4a:"mp4"} - * @static - */ - s.EXTENSION_MAP = { - m4a:"mp4" - }; - - /** - * The RegExp pattern used to parse file URIs. This supports simple file names, as well as full domain URIs with - * query strings. The resulting match is: protocol:$1 domain:$2 path:$3 file:$4 extension:$5 query:$6. - * @property FILE_PATTERN - * @type {RegExp} - * @static - * @protected - */ - s.FILE_PATTERN = /^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/; - - -// Class Public properties - /** - * Determines the default behavior for interrupting other currently playing instances with the same source, if the - * maximum number of instances of the sound are already playing. Currently the default is {{#crossLink "Sound/INTERRUPT_NONE:property"}}{{/crossLink}} - * but this can be set and will change playback behavior accordingly. This is only used when {{#crossLink "Sound/play"}}{{/crossLink}} - * is called without passing a value for interrupt. - * @property defaultInterruptBehavior - * @type {String} - * @default Sound.INTERRUPT_NONE, or "none" - * @static - * @since 0.4.0 - */ - s.defaultInterruptBehavior = s.INTERRUPT_NONE; // OJR does s.INTERRUPT_ANY make more sense as default? Needs game dev testing to see which case makes more sense. - - /** - * An array of extensions to attempt to use when loading sound, if the default is unsupported by the active plugin. - * These are applied in order, so if you try to Load Thunder.ogg in a browser that does not support ogg, and your - * extensions array is ["mp3", "m4a", "wav"] it will check mp3 support, then m4a, then wav. The audio files need - * to exist in the same location, as only the extension is altered. - * - * Note that regardless of which file is loaded, you can call {{#crossLink "Sound/createInstance"}}{{/crossLink}} - * and {{#crossLink "Sound/play"}}{{/crossLink}} using the same id or full source path passed for loading. - * - *

        Example

        - * - * var sounds = [ - * {src:"myPath/mySound.ogg", id:"example"}, - * ]; - * createjs.Sound.alternateExtensions = ["mp3"]; // now if ogg is not supported, SoundJS will try asset0.mp3 - * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads - * createjs.Sound.registerSounds(sounds, assetPath); - * // ... - * createjs.Sound.play("myPath/mySound.ogg"); // works regardless of what extension is supported. Note calling with ID is a better approach - * - * @property alternateExtensions - * @type {Array} - * @since 0.5.2 - * @static - */ - s.alternateExtensions = []; - - /** - * The currently active plugin. If this is null, then no plugin could be initialized. If no plugin was specified, - * Sound attempts to apply the default plugins: {{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by - * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}. - * @property activePlugin - * @type {Object} - * @static - */ - s.activePlugin = null; - - -// class getter / setter properties - /** - * Set the master volume of Sound. The master volume is multiplied against each sound's individual volume. For - * example, if master volume is 0.5 and a sound's volume is 0.5, the resulting volume is 0.25. To set individual - * sound volume, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} instead. - * - *

        Example

        - * - * createjs.Sound.volume = 0.5; - * - * - * @property volume - * @type {Number} - * @default 1 - * @since 0.6.1 - */ - s._masterVolume = 1; - Object.defineProperty(s, "volume", { - get: function () {return this._masterVolume;}, - set: function (value) { - if (Number(value) == null) {return false;} - value = Math.max(0, Math.min(1, value)); - s._masterVolume = value; - if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) { - var instances = this._instances; - for (var i = 0, l = instances.length; i < l; i++) { - instances[i].setMasterVolume(value); - } - } - } - }); - - /** - * Mute/Unmute all audio. Note that muted audio still plays at 0 volume. This global mute value is maintained - * separately and when set will override, but not change the mute property of individual instances. To mute an individual - * instance, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} instead. - * - *

        Example

        - * - * createjs.Sound.muted = true; - * - * - * @property muted - * @type {Boolean} - * @default false - * @since 0.6.1 - */ - s._masterMute = false; - // OJR references to the methods were not working, so the code had to be duplicated here - Object.defineProperty(s, "muted", { - get: function () {return this._masterMute;}, - set: function (value) { - if (value == null) {return false;} - - this._masterMute = value; - if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) { - var instances = this._instances; - for (var i = 0, l = instances.length; i < l; i++) { - instances[i].setMasterMute(value); - } - } - return true; - } - }); - - /** - * Get the active plugins capabilities, which help determine if a plugin can be used in the current environment, - * or if the plugin supports a specific feature. Capabilities include: - *
          - *
        • panning: If the plugin can pan audio from left to right
        • - *
        • volume; If the plugin can control audio volume.
        • - *
        • tracks: The maximum number of audio tracks that can be played back at a time. This will be -1 - * if there is no known limit.
        • - *
          An entry for each file type in {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}: - *
        • mp3: If MP3 audio is supported.
        • - *
        • ogg: If OGG audio is supported.
        • - *
        • wav: If WAV audio is supported.
        • - *
        • mpeg: If MPEG audio is supported.
        • - *
        • m4a: If M4A audio is supported.
        • - *
        • mp4: If MP4 audio is supported.
        • - *
        • aiff: If aiff audio is supported.
        • - *
        • wma: If wma audio is supported.
        • - *
        • mid: If mid audio is supported.
        • - *
        - * - * You can get a specific capability of the active plugin using standard object notation - * - *

        Example

        - * - * var mp3 = createjs.Sound.capabilities.mp3; - * - * Note this property is read only. - * - * @property capabilities - * @type {Object} - * @static - * @readOnly - * @since 0.6.1 - */ - Object.defineProperty(s, "capabilities", { - get: function () { - if (s.activePlugin == null) {return null;} - return s.activePlugin._capabilities; - }, - set: function (value) { return false;} - }); - - -// Class Private properties - /** - * Determines if the plugins have been registered. If false, the first call to play() will instantiate the default - * plugins ({{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}). - * If plugins have been registered, but none are applicable, then sound playback will fail. - * @property _pluginsRegistered - * @type {Boolean} - * @default false - * @static - * @protected - */ - s._pluginsRegistered = false; - - /** - * Used internally to assign unique IDs to each AbstractSoundInstance. - * @property _lastID - * @type {Number} - * @static - * @protected - */ - s._lastID = 0; - - /** - * An array containing all currently playing instances. This allows Sound to control the volume, mute, and playback of - * all instances when using static APIs like {{#crossLink "Sound/stop"}}{{/crossLink}} and {{#crossLink "Sound/setVolume"}}{{/crossLink}}. - * When an instance has finished playback, it gets removed via the {{#crossLink "Sound/finishedPlaying"}}{{/crossLink}} - * method. If the user replays an instance, it gets added back in via the {{#crossLink "Sound/_beginPlaying"}}{{/crossLink}} - * method. - * @property _instances - * @type {Array} - * @protected - * @static - */ - s._instances = []; - - /** - * An object hash storing objects with sound sources, startTime, and duration via there corresponding ID. - * @property _idHash - * @type {Object} - * @protected - * @static - */ - s._idHash = {}; - - /** - * An object hash that stores preloading sound sources via the parsed source that is passed to the plugin. Contains the - * source, id, and data that was passed in by the user. Parsed sources can contain multiple instances of source, id, - * and data. - * @property _preloadHash - * @type {Object} - * @protected - * @static - */ - s._preloadHash = {}; - - /** - * An object hash storing {{#crossLink "PlayPropsConfig"}}{{/crossLink}} via the parsed source that is passed as defaultPlayProps in - * {{#crossLink "Sound/registerSound"}}{{/crossLink}} and {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. - * @property _defaultPlayPropsHash - * @type {Object} - * @protected - * @static - * @since 0.6.1 - */ - s._defaultPlayPropsHash = {}; - - -// EventDispatcher methods: - s.addEventListener = null; - s.removeEventListener = null; - s.removeAllEventListeners = null; - s.dispatchEvent = null; - s.hasEventListener = null; - s._listeners = null; - - createjs.EventDispatcher.initialize(s); // inject EventDispatcher methods. - - -// Events - /** - * This event is fired when a file finishes loading internally. This event is fired for each loaded sound, - * so any handler methods should look up the event.src to handle a particular sound. - * @event fileload - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {String} src The source of the sound that was loaded. - * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null. - * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined. - * @since 0.4.1 - */ - - /** - * This event is fired when a file fails loading internally. This event is fired for each loaded sound, - * so any handler methods should look up the event.src to handle a particular sound. - * @event fileerror - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @param {String} src The source of the sound that was loaded. - * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null. - * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined. - * @since 0.6.0 - */ - - -// Class Public Methods - /** - * Get the preload rules to allow Sound to be used as a plugin by PreloadJS. - * Any load calls that have the matching type or extension will fire the callback method, and use the resulting - * object, which is potentially modified by Sound. This helps when determining the correct path, as well as - * registering the audio instance(s) with Sound. This method should not be called, except by PreloadJS. - * @method getPreloadHandlers - * @return {Object} An object containing: - *
        • callback: A preload callback that is fired when a file is added to PreloadJS, which provides - * Sound a mechanism to modify the load parameters, select the correct file format, register the sound, etc.
        • - *
        • types: A list of file types that are supported by Sound (currently supports "sound").
        • - *
        • extensions: A list of file extensions that are supported by Sound (see {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}).
        - * @static - * @protected - */ - s.getPreloadHandlers = function () { - return { - callback:createjs.proxy(s.initLoad, s), - types:["sound"], - extensions:s.SUPPORTED_EXTENSIONS - }; - }; - - /** - * Used to dispatch fileload events from internal loading. - * @method _handleLoadComplete - * @param event A loader event. - * @protected - * @static - * @since 0.6.0 - */ - s._handleLoadComplete = function(event) { - var src = event.target.getItem().src; - if (!s._preloadHash[src]) {return;} - - for (var i = 0, l = s._preloadHash[src].length; i < l; i++) { - var item = s._preloadHash[src][i]; - s._preloadHash[src][i] = true; - - if (!s.hasEventListener("fileload")) { continue; } - - var event = new createjs.Event("fileload"); - event.src = item.src; - event.id = item.id; - event.data = item.data; - event.sprite = item.sprite; - - s.dispatchEvent(event); - } - }; - - /** - * Used to dispatch error events from internal preloading. - * @param event - * @protected - * @since 0.6.0 - * @static - */ - s._handleLoadError = function(event) { - var src = event.target.getItem().src; - if (!s._preloadHash[src]) {return;} - - for (var i = 0, l = s._preloadHash[src].length; i < l; i++) { - var item = s._preloadHash[src][i]; - s._preloadHash[src][i] = false; - - if (!s.hasEventListener("fileerror")) { continue; } - - var event = new createjs.Event("fileerror"); - event.src = item.src; - event.id = item.id; - event.data = item.data; - event.sprite = item.sprite; - - s.dispatchEvent(event); - } - }; - - /** - * Used by {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} to register a Sound plugin. - * - * @method _registerPlugin - * @param {Object} plugin The plugin class to install. - * @return {Boolean} Whether the plugin was successfully initialized. - * @static - * @private - */ - s._registerPlugin = function (plugin) { - // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance - if (plugin.isSupported()) { - s.activePlugin = new plugin(); - return true; - } - return false; - }; - - /** - * Register a list of Sound plugins, in order of precedence. To register a single plugin, pass a single element in the array. - * - *

        Example

        - * - * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/"; - * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]); - * - * @method registerPlugins - * @param {Array} plugins An array of plugins classes to install. - * @return {Boolean} Whether a plugin was successfully initialized. - * @static - */ - s.registerPlugins = function (plugins) { - s._pluginsRegistered = true; - for (var i = 0, l = plugins.length; i < l; i++) { - if (s._registerPlugin(plugins[i])) { - return true; - } - } - return false; - }; - - /** - * Initialize the default plugins. This method is automatically called when any audio is played or registered before - * the user has manually registered plugins, and enables Sound to work without manual plugin setup. Currently, the - * default plugins are {{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}. - * - *

        Example

        - * - * if (!createjs.initializeDefaultPlugins()) { return; } - * - * @method initializeDefaultPlugins - * @returns {Boolean} True if a plugin was initialized, false otherwise. - * @since 0.4.0 - * @static - */ - s.initializeDefaultPlugins = function () { - if (s.activePlugin != null) {return true;} - if (s._pluginsRegistered) {return false;} - if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) {return true;} - return false; - }; - - /** - * Determines if Sound has been initialized, and a plugin has been activated. - * - *

        Example

        - * This example sets up a Flash fallback, but only if there is no plugin specified yet. - * - * if (!createjs.Sound.isReady()) { - * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/"; - * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]); - * } - * - * @method isReady - * @return {Boolean} If Sound has initialized a plugin. - * @static - */ - s.isReady = function () { - return (s.activePlugin != null); - }; - - /** - * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead. - * - * @method getCapabilities - * @return {Object} An object containing the capabilities of the active plugin. - * @static - * @deprecated - */ - s.getCapabilities = function () { - if (s.activePlugin == null) {return null;} - return s.activePlugin._capabilities; - }; - - /** - * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead. - * - * @method getCapability - * @param {String} key The capability to retrieve - * @return {Number|Boolean} The value of the capability. - * @static - * @see getCapabilities - * @deprecated - */ - s.getCapability = function (key) { - if (s.activePlugin == null) {return null;} - return s.activePlugin._capabilities[key]; - }; - - /** - * Process manifest items from PreloadJS. This method is intended - * for usage by a plugin, and not for direct interaction. - * @method initLoad - * @param {Object} src The object to load. - * @return {Object|AbstractLoader} An instance of AbstractLoader. - * @protected - * @static - */ - s.initLoad = function (loadItem) { - return s._registerSound(loadItem); - }; - - /** - * Internal method for loading sounds. This should not be called directly. - * - * @method _registerSound - * @param {Object} src The object to load, containing src property and optionally containing id and data. - * @return {Object} An object with the modified values that were passed in, which defines the sound. - * Returns false if the source cannot be parsed or no plugins can be initialized. - * Returns true if the source is already loaded. - * @static - * @private - * @since 0.6.0 - */ - - s._registerSound = function (loadItem) { - if (!s.initializeDefaultPlugins()) {return false;} - - var details; - if (loadItem.src instanceof Object) { - details = s._parseSrc(loadItem.src); - details.src = loadItem.path + details.src; - } else { - details = s._parsePath(loadItem.src); - } - if (details == null) {return false;} - loadItem.src = details.src; - loadItem.type = "sound"; - - var data = loadItem.data; - var numChannels = null; - if (data != null) { - if (!isNaN(data.channels)) { - numChannels = parseInt(data.channels); - } else if (!isNaN(data)) { - numChannels = parseInt(data); - } - - if(data.audioSprite) { - var sp; - for(var i = data.audioSprite.length; i--; ) { - sp = data.audioSprite[i]; - s._idHash[sp.id] = {src: loadItem.src, startTime: parseInt(sp.startTime), duration: parseInt(sp.duration)}; - - if (sp.defaultPlayProps) { - s._defaultPlayPropsHash[sp.id] = createjs.PlayPropsConfig.create(sp.defaultPlayProps); - } - } - } - } - if (loadItem.id != null) {s._idHash[loadItem.id] = {src: loadItem.src}}; - var loader = s.activePlugin.register(loadItem); - - SoundChannel.create(loadItem.src, numChannels); - - // return the number of instances to the user. This will also be returned in the load event. - if (data == null || !isNaN(data)) { - loadItem.data = numChannels || SoundChannel.maxPerChannel(); - } else { - loadItem.data.channels = numChannels || SoundChannel.maxPerChannel(); - } - - if (loader.type) {loadItem.type = loader.type;} - - if (loadItem.defaultPlayProps) { - s._defaultPlayPropsHash[loadItem.src] = createjs.PlayPropsConfig.create(loadItem.defaultPlayProps); - } - return loader; - }; - - /** - * Register an audio file for loading and future playback in Sound. This is automatically called when using - * PreloadJS. It is recommended to register all sounds that - * need to be played back in order to properly prepare and preload them. Sound does internal preloading when required. - * - *

        Example

        - * - * createjs.Sound.alternateExtensions = ["mp3"]; - * createjs.Sound.on("fileload", handleLoad); // add an event listener for when load is completed - * createjs.Sound.registerSound("myAudioPath/mySound.ogg", "myID", 3); - * createjs.Sound.registerSound({ogg:"path1/mySound.ogg", mp3:"path2/mySoundNoExtension"}, "myID", 3); - * - * - * @method registerSound - * @param {String | Object} src The source or an Object with a "src" property or an Object with multiple extension labeled src properties. - * @param {String} [id] An id specified by the user to play the sound later. Note id is required for when src is multiple extension labeled src properties. - * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of - * channels for an audio instance, however a "channels" property can be appended to the data object if it is used - * for other information. The audio channels will set a default based on plugin if no value is found. - * Sound also uses the data property to hold an {{#crossLink "AudioSprite"}}{{/crossLink}} array of objects in the following format {id, startTime, duration}.
        - * id used to play the sound later, in the same manner as a sound src with an id.
        - * startTime is the initial offset to start playback and loop from, in milliseconds.
        - * duration is the amount of time to play the clip for, in milliseconds.
        - * This allows Sound to support audio sprites that are played back by id. - * @param {string} basePath Set a path that will be prepended to src for loading. - * @param {Object | PlayPropsConfig} defaultPlayProps Optional Playback properties that will be set as the defaults on any new AbstractSoundInstance. - * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for options. - * @return {Object} An object with the modified values that were passed in, which defines the sound. - * Returns false if the source cannot be parsed or no plugins can be initialized. - * Returns true if the source is already loaded. - * @static - * @since 0.4.0 - */ - s.registerSound = function (src, id, data, basePath, defaultPlayProps) { - var loadItem = {src: src, id: id, data:data, defaultPlayProps:defaultPlayProps}; - if (src instanceof Object && src.src) { - basePath = id; - loadItem = src; - } - loadItem = createjs.LoadItem.create(loadItem); - loadItem.path = basePath; - - if (basePath != null && !(loadItem.src instanceof Object)) {loadItem.src = basePath + src;} - - var loader = s._registerSound(loadItem); - if(!loader) {return false;} - - if (!s._preloadHash[loadItem.src]) { s._preloadHash[loadItem.src] = [];} - s._preloadHash[loadItem.src].push(loadItem); - if (s._preloadHash[loadItem.src].length == 1) { - // OJR note this will disallow reloading a sound if loading fails or the source changes - loader.on("complete", createjs.proxy(this._handleLoadComplete, this)); - loader.on("error", createjs.proxy(this._handleLoadError, this)); - s.activePlugin.preload(loader); - } else { - if (s._preloadHash[loadItem.src][0] == true) {return true;} - } - - return loadItem; - }; - - /** - * Register an array of audio files for loading and future playback in Sound. It is recommended to register all - * sounds that need to be played back in order to properly prepare and preload them. Sound does internal preloading - * when required. - * - *

        Example

        - * - * var assetPath = "./myAudioPath/"; - * var sounds = [ - * {src:"asset0.ogg", id:"example"}, - * {src:"asset1.ogg", id:"1", data:6}, - * {src:"asset2.mp3", id:"works"} - * {src:{mp3:"path1/asset3.mp3", ogg:"path2/asset3NoExtension"}, id:"better"} - * ]; - * createjs.Sound.alternateExtensions = ["mp3"]; // if the passed extension is not supported, try this extension - * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads - * createjs.Sound.registerSounds(sounds, assetPath); - * - * @method registerSounds - * @param {Array} sounds An array of objects to load. Objects are expected to be in the format needed for - * {{#crossLink "Sound/registerSound"}}{{/crossLink}}: {src:srcURI, id:ID, data:Data} - * with "id" and "data" being optional. - * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to load. - * Note id is required if src is an object with extension labeled src properties. - * @param {string} basePath Set a path that will be prepended to each src when loading. When creating, playing, or removing - * audio that was loaded with a basePath by src, the basePath must be included. - * @return {Object} An array of objects with the modified values that were passed in, which defines each sound. - * Like registerSound, it will return false for any values when the source cannot be parsed or if no plugins can be initialized. - * Also, it will return true for any values when the source is already loaded. - * @static - * @since 0.6.0 - */ - s.registerSounds = function (sounds, basePath) { - var returnValues = []; - if (sounds.path) { - if (!basePath) { - basePath = sounds.path; - } else { - basePath = basePath + sounds.path; - } - sounds = sounds.manifest; - // TODO document this feature - } - for (var i = 0, l = sounds.length; i < l; i++) { - returnValues[i] = createjs.Sound.registerSound(sounds[i].src, sounds[i].id, sounds[i].data, basePath, sounds[i].defaultPlayProps); - } - return returnValues; - }; - - /** - * Remove a sound that has been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or - * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. - *
        Note this will stop playback on active instances playing this sound before deleting them. - *
        Note if you passed in a basePath, you need to pass it or prepend it to the src here. - * - *

        Example

        - * - * createjs.Sound.removeSound("myID"); - * createjs.Sound.removeSound("myAudioBasePath/mySound.ogg"); - * createjs.Sound.removeSound("myPath/myOtherSound.mp3", "myBasePath/"); - * createjs.Sound.removeSound({mp3:"musicNoExtension", ogg:"music.ogg"}, "myBasePath/"); - * - * @method removeSound - * @param {String | Object} src The src or ID of the audio, or an Object with a "src" property, or an Object with multiple extension labeled src properties. - * @param {string} basePath Set a path that will be prepended to each src when removing. - * @return {Boolean} True if sound is successfully removed. - * @static - * @since 0.4.1 - */ - s.removeSound = function(src, basePath) { - if (s.activePlugin == null) {return false;} - - if (src instanceof Object && src.src) {src = src.src;} - - var details; - if (src instanceof Object) { - details = s._parseSrc(src); - } else { - src = s._getSrcById(src).src; - details = s._parsePath(src); - } - if (details == null) {return false;} - src = details.src; - if (basePath != null) {src = basePath + src;} - - for(var prop in s._idHash){ - if(s._idHash[prop].src == src) { - delete(s._idHash[prop]); - } - } - - // clear from SoundChannel, which also stops and deletes all instances - SoundChannel.removeSrc(src); - - delete(s._preloadHash[src]); - - s.activePlugin.removeSound(src); - - return true; - }; - - /** - * Remove an array of audio files that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or - * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. - *
        Note this will stop playback on active instances playing this audio before deleting them. - *
        Note if you passed in a basePath, you need to pass it or prepend it to the src here. - * - *

        Example

        - * - * assetPath = "./myPath/"; - * var sounds = [ - * {src:"asset0.ogg", id:"example"}, - * {src:"asset1.ogg", id:"1", data:6}, - * {src:"asset2.mp3", id:"works"} - * ]; - * createjs.Sound.removeSounds(sounds, assetPath); - * - * @method removeSounds - * @param {Array} sounds An array of objects to remove. Objects are expected to be in the format needed for - * {{#crossLink "Sound/removeSound"}}{{/crossLink}}: {srcOrID:srcURIorID}. - * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to remove. - * @param {string} basePath Set a path that will be prepended to each src when removing. - * @return {Object} An array of Boolean values representing if the sounds with the same array index were - * successfully removed. - * @static - * @since 0.4.1 - */ - s.removeSounds = function (sounds, basePath) { - var returnValues = []; - if (sounds.path) { - if (!basePath) { - basePath = sounds.path; - } else { - basePath = basePath + sounds.path; - } - sounds = sounds.manifest; - } - for (var i = 0, l = sounds.length; i < l; i++) { - returnValues[i] = createjs.Sound.removeSound(sounds[i].src, basePath); - } - return returnValues; - }; - - /** - * Remove all sounds that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or - * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. - *
        Note this will stop playback on all active sound instances before deleting them. - * - *

        Example

        - * - * createjs.Sound.removeAllSounds(); - * - * @method removeAllSounds - * @static - * @since 0.4.1 - */ - s.removeAllSounds = function() { - s._idHash = {}; - s._preloadHash = {}; - SoundChannel.removeAll(); - if (s.activePlugin) {s.activePlugin.removeAllSounds();} - }; - - /** - * Check if a source has been loaded by internal preloaders. This is necessary to ensure that sounds that are - * not completed preloading will not kick off a new internal preload if they are played. - * - *

        Example

        - * - * var mySound = "assetPath/asset0.ogg"; - * if(createjs.Sound.loadComplete(mySound) { - * createjs.Sound.play(mySound); - * } - * - * @method loadComplete - * @param {String} src The src or id that is being loaded. - * @return {Boolean} If the src is already loaded. - * @since 0.4.0 - * @static - */ - s.loadComplete = function (src) { - if (!s.isReady()) { return false; } - var details = s._parsePath(src); - if (details) { - src = s._getSrcById(details.src).src; - } else { - src = s._getSrcById(src).src; - } - if(s._preloadHash[src] == undefined) {return false;} - return (s._preloadHash[src][0] == true); // src only loads once, so if it's true for the first it's true for all - }; - - /** - * Parse the path of a sound. Alternate extensions will be attempted in order if the - * current extension is not supported - * @method _parsePath - * @param {String} value The path to an audio source. - * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}} - * and returned to a preloader like PreloadJS. - * @protected - * @static - */ - s._parsePath = function (value) { - if (typeof(value) != "string") {value = value.toString();} - - var match = value.match(s.FILE_PATTERN); - if (match == null) {return false;} - - var name = match[4]; - var ext = match[5]; - var c = s.capabilities; - var i = 0; - while (!c[ext]) { - ext = s.alternateExtensions[i++]; - if (i > s.alternateExtensions.length) { return null;} // no extensions are supported - } - value = value.replace("."+match[5], "."+ext); - - var ret = {name:name, src:value, extension:ext}; - return ret; - }; - - /** - * Parse the path of a sound based on properties of src matching with supported extensions. - * Returns false if none of the properties are supported - * @method _parseSrc - * @param {Object} value The paths to an audio source, indexed by extension type. - * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}} - * and returned to a preloader like PreloadJS. - * @protected - * @static - */ - s._parseSrc = function (value) { - var ret = {name:undefined, src:undefined, extension:undefined}; - var c = s.capabilities; - - for (var prop in value) { - if(value.hasOwnProperty(prop) && c[prop]) { - ret.src = value[prop]; - ret.extension = prop; - break; - } - } - if (!ret.src) {return false;} // no matches - - var i = ret.src.lastIndexOf("/"); - if (i != -1) { - ret.name = ret.src.slice(i+1); - } else { - ret.name = ret.src; - } - - return ret; - }; - - /* --------------- - Static API. - --------------- */ - /** - * Play a sound and get a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to control. If the sound fails to play, a - * AbstractSoundInstance will still be returned, and have a playState of {{#crossLink "Sound/PLAY_FAILED:property"}}{{/crossLink}}. - * Note that even on sounds with failed playback, you may still be able to call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}, - * since the failure could be due to lack of available channels. If the src does not have a supported extension or - * if there is no available plugin, a default AbstractSoundInstance will be returned which will not play any audio, but will not generate errors. - * - *

        Example

        - * - * createjs.Sound.on("fileload", handleLoad); - * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3); - * function handleLoad(event) { - * createjs.Sound.play("myID"); - * // store off AbstractSoundInstance for controlling - * var myInstance = createjs.Sound.play("myID", {interrupt: createjs.Sound.INTERRUPT_ANY, loop:-1}); - * } - * - * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set. - * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite. - * - * Parameters Deprecated
        - * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}. - * - * @method play - * @param {String} src The src or ID of the audio. - * @param {String | Object} [interrupt="none"|options] This parameter will be renamed playProps in the next release.
        - * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name, - * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample). - *
        OR
        - * Deprecated How to interrupt any currently playing instances of audio with the same source, - * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE - * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}. - * @param {Number} [delay=0] Deprecated The amount of time to delay the start of audio playback, in milliseconds. - * @param {Number} [offset=0] Deprecated The offset from the start of the audio to begin playback, in milliseconds. - * @param {Number} [loop=0] Deprecated How many times the audio loops when it reaches the end of playback. The default is 0 (no - * loops), and -1 can be used for infinite playback. - * @param {Number} [volume=1] Deprecated The volume of the sound, between 0 and 1. Note that the master volume is applied - * against the individual volume. - * @param {Number} [pan=0] Deprecated The left-right pan of the sound (if supported), between -1 (left) and 1 (right). - * @param {Number} [startTime=null] Deprecated To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds. - * @param {Number} [duration=null] Deprecated To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds. - * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created. - * @static - */ - s.play = function (src, interrupt, delay, offset, loop, volume, pan, startTime, duration) { - var playProps; - if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) { - playProps = createjs.PlayPropsConfig.create(interrupt); - } else { - playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan, startTime:startTime, duration:duration}); - } - var instance = s.createInstance(src, playProps.startTime, playProps.duration); - var ok = s._playInstance(instance, playProps); - if (!ok) {instance._playFailed();} - return instance; - }; - - /** - * Creates a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} using the passed in src. If the src does not have a - * supported extension or if there is no available plugin, a default AbstractSoundInstance will be returned that can be - * called safely but does nothing. - * - *

        Example

        - * - * var myInstance = null; - * createjs.Sound.on("fileload", handleLoad); - * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3); - * function handleLoad(event) { - * myInstance = createjs.Sound.createInstance("myID"); - * // alternately we could call the following - * myInstance = createjs.Sound.createInstance("myAudioPath/mySound.mp3"); - * } - * - * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set. - * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite. - * - * @method createInstance - * @param {String} src The src or ID of the audio. - * @param {Number} [startTime=null] To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds. - * @param {Number} [duration=null] To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds. - * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created. - * Unsupported extensions will return the default AbstractSoundInstance. - * @since 0.4.0 - * @static - */ - s.createInstance = function (src, startTime, duration) { - if (!s.initializeDefaultPlugins()) {return new createjs.DefaultSoundInstance(src, startTime, duration);} - - var defaultPlayProps = s._defaultPlayPropsHash[src]; // for audio sprites, which create and store defaults by id - src = s._getSrcById(src); - - var details = s._parsePath(src.src); - - var instance = null; - if (details != null && details.src != null) { - SoundChannel.create(details.src); - if (startTime == null) {startTime = src.startTime;} - instance = s.activePlugin.create(details.src, startTime, duration || src.duration); - - defaultPlayProps = defaultPlayProps || s._defaultPlayPropsHash[details.src]; - if(defaultPlayProps) { - instance.applyPlayProps(defaultPlayProps); - } - } else { - instance = new createjs.DefaultSoundInstance(src, startTime, duration); - } - - instance.uniqueId = s._lastID++; - - return instance; - }; - - /** - * Stop all audio (global stop). Stopped audio is reset, and not paused. To play audio that has been stopped, - * call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}. - * - *

        Example

        - * - * createjs.Sound.stop(); - * - * @method stop - * @static - */ - s.stop = function () { - var instances = this._instances; - for (var i = instances.length; i--; ) { - instances[i].stop(); // NOTE stop removes instance from this._instances - } - }; - - /** - * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead. - * - * @method setVolume - * @param {Number} value The master volume value. The acceptable range is 0-1. - * @static - * @deprecated - */ - s.setVolume = function (value) { - if (Number(value) == null) {return false;} - value = Math.max(0, Math.min(1, value)); - s._masterVolume = value; - if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) { - var instances = this._instances; - for (var i = 0, l = instances.length; i < l; i++) { - instances[i].setMasterVolume(value); - } - } - }; - - /** - * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead. - * - * @method getVolume - * @return {Number} The master volume, in a range of 0-1. - * @static - * @deprecated - */ - s.getVolume = function () { - return this._masterVolume; - }; - - /** - * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead. - * - * @method setMute - * @param {Boolean} value Whether the audio should be muted or not. - * @return {Boolean} If the mute was set. - * @static - * @since 0.4.0 - * @deprecated - */ - s.setMute = function (value) { - if (value == null) {return false;} - - this._masterMute = value; - if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) { - var instances = this._instances; - for (var i = 0, l = instances.length; i < l; i++) { - instances[i].setMasterMute(value); - } - } - return true; - }; - - /** - * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead. - * - * @method getMute - * @return {Boolean} The mute value of Sound. - * @static - * @since 0.4.0 - * @deprecated - */ - s.getMute = function () { - return this._masterMute; - }; - - /** - * Set the default playback properties for all new SoundInstances of the passed in src or ID. - * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for available properties. - * - * @method setDefaultPlayProps - * @param {String} src The src or ID used to register the audio. - * @param {Object | PlayPropsConfig} playProps The playback properties you would like to set. - * @since 0.6.1 - */ - s.setDefaultPlayProps = function(src, playProps) { - src = s._getSrcById(src); - s._defaultPlayPropsHash[s._parsePath(src.src).src] = createjs.PlayPropsConfig.create(playProps); - }; - - /** - * Get the default playback properties for the passed in src or ID. These properties are applied to all - * new SoundInstances. Returns null if default does not exist. - * - * @method getDefaultPlayProps - * @param {String} src The src or ID used to register the audio. - * @returns {PlayPropsConfig} returns an existing PlayPropsConfig or null if one does not exist - * @since 0.6.1 - */ - s.getDefaultPlayProps = function(src) { - src = s._getSrcById(src); - return s._defaultPlayPropsHash[s._parsePath(src.src).src]; - }; - - - /* --------------- - Internal methods - --------------- */ - /** - * Play an instance. This is called by the static API, as well as from plugins. This allows the core class to - * control delays. - * @method _playInstance - * @param {AbstractSoundInstance} instance The {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to start playing. - * @param {PlayPropsConfig} playProps A PlayPropsConfig object. - * @return {Boolean} If the sound can start playing. Sounds that fail immediately will return false. Sounds that - * have a delay will return true, but may still fail to play. - * @protected - * @static - */ - s._playInstance = function (instance, playProps) { - var defaultPlayProps = s._defaultPlayPropsHash[instance.src] || {}; - if (playProps.interrupt == null) {playProps.interrupt = defaultPlayProps.interrupt || s.defaultInterruptBehavior}; - if (playProps.delay == null) {playProps.delay = defaultPlayProps.delay || 0;} - if (playProps.offset == null) {playProps.offset = instance.getPosition();} - if (playProps.loop == null) {playProps.loop = instance.loop;} - if (playProps.volume == null) {playProps.volume = instance.volume;} - if (playProps.pan == null) {playProps.pan = instance.pan;} - - if (playProps.delay == 0) { - var ok = s._beginPlaying(instance, playProps); - if (!ok) {return false;} - } else { - //Note that we can't pass arguments to proxy OR setTimeout (IE only), so just wrap the function call. - // OJR WebAudio may want to handle this differently, so it might make sense to move this functionality into the plugins in the future - var delayTimeoutId = setTimeout(function () { - s._beginPlaying(instance, playProps); - }, playProps.delay); - instance.delayTimeoutId = delayTimeoutId; - } - - this._instances.push(instance); - - return true; - }; - - /** - * Begin playback. This is called immediately or after delay by {{#crossLink "Sound/playInstance"}}{{/crossLink}}. - * @method _beginPlaying - * @param {AbstractSoundInstance} instance A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to begin playback. - * @param {PlayPropsConfig} playProps A PlayPropsConfig object. - * @return {Boolean} If the sound can start playing. If there are no available channels, or the instance fails to - * start, this will return false. - * @protected - * @static - */ - s._beginPlaying = function (instance, playProps) { - if (!SoundChannel.add(instance, playProps.interrupt)) { - return false; - } - var result = instance._beginPlaying(playProps); - if (!result) { - var index = createjs.indexOf(this._instances, instance); - if (index > -1) {this._instances.splice(index, 1);} - return false; - } - return true; - }; - - /** - * Get the source of a sound via the ID passed in with a register call. If no ID is found the value is returned - * instead. - * @method _getSrcById - * @param {String} value The ID the sound was registered with. - * @return {String} The source of the sound if it has been registered with this ID or the value that was passed in. - * @protected - * @static - */ - s._getSrcById = function (value) { - return s._idHash[value] || {src: value}; - }; - - /** - * A sound has completed playback, been interrupted, failed, or been stopped. This method removes the instance from - * Sound management. It will be added again, if the sound re-plays. Note that this method is called from the - * instances themselves. - * @method _playFinished - * @param {AbstractSoundInstance} instance The instance that finished playback. - * @protected - * @static - */ - s._playFinished = function (instance) { - SoundChannel.remove(instance); - var index = createjs.indexOf(this._instances, instance); - if (index > -1) {this._instances.splice(index, 1);} // OJR this will always be > -1, there is no way for an instance to exist without being added to this._instances - }; - - createjs.Sound = Sound; - - /** - * An internal class that manages the number of active {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} instances for - * each sound type. This method is only used internally by the {{#crossLink "Sound"}}{{/crossLink}} class. - * - * The number of sounds is artificially limited by Sound in order to prevent over-saturation of a - * single sound, as well as to stay within hardware limitations, although the latter may disappear with better - * browser support. - * - * When a sound is played, this class ensures that there is an available instance, or interrupts an appropriate - * sound that is already playing. - * #class SoundChannel - * @param {String} src The source of the instances - * @param {Number} [max=1] The number of instances allowed - * @constructor - * @protected - */ - function SoundChannel(src, max) { - this.init(src, max); - } - - /* ------------ - Static API - ------------ */ - /** - * A hash of channel instances indexed by source. - * #property channels - * @type {Object} - * @static - */ - SoundChannel.channels = {}; - - /** - * Create a sound channel. Note that if the sound channel already exists, this will fail. - * #method create - * @param {String} src The source for the channel - * @param {Number} max The maximum amount this channel holds. The default is {{#crossLink "SoundChannel.maxDefault"}}{{/crossLink}}. - * @return {Boolean} If the channels were created. - * @static - */ - SoundChannel.create = function (src, max) { - var channel = SoundChannel.get(src); - if (channel == null) { - SoundChannel.channels[src] = new SoundChannel(src, max); - return true; - } - return false; - }; - /** - * Delete a sound channel, stop and delete all related instances. Note that if the sound channel does not exist, this will fail. - * #method remove - * @param {String} src The source for the channel - * @return {Boolean} If the channels were deleted. - * @static - */ - SoundChannel.removeSrc = function (src) { - var channel = SoundChannel.get(src); - if (channel == null) {return false;} - channel._removeAll(); // this stops and removes all active instances - delete(SoundChannel.channels[src]); - return true; - }; - /** - * Delete all sound channels, stop and delete all related instances. - * #method removeAll - * @static - */ - SoundChannel.removeAll = function () { - for(var channel in SoundChannel.channels) { - SoundChannel.channels[channel]._removeAll(); // this stops and removes all active instances - } - SoundChannel.channels = {}; - }; - /** - * Add an instance to a sound channel. - * #method add - * @param {AbstractSoundInstance} instance The instance to add to the channel - * @param {String} interrupt The interrupt value to use. Please see the {{#crossLink "Sound/play"}}{{/crossLink}} - * for details on interrupt modes. - * @return {Boolean} The success of the method call. If the channel is full, it will return false. - * @static - */ - SoundChannel.add = function (instance, interrupt) { - var channel = SoundChannel.get(instance.src); - if (channel == null) {return false;} - return channel._add(instance, interrupt); - }; - /** - * Remove an instance from the channel. - * #method remove - * @param {AbstractSoundInstance} instance The instance to remove from the channel - * @return The success of the method call. If there is no channel, it will return false. - * @static - */ - SoundChannel.remove = function (instance) { - var channel = SoundChannel.get(instance.src); - if (channel == null) {return false;} - channel._remove(instance); - return true; - }; - /** - * Get the maximum number of sounds you can have in a channel. - * #method maxPerChannel - * @return {Number} The maximum number of sounds you can have in a channel. - */ - SoundChannel.maxPerChannel = function () { - return p.maxDefault; - }; - /** - * Get a channel instance by its src. - * #method get - * @param {String} src The src to use to look up the channel - * @static - */ - SoundChannel.get = function (src) { - return SoundChannel.channels[src]; - }; - - var p = SoundChannel.prototype; - p.constructor = SoundChannel; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - - /** - * The source of the channel. - * #property src - * @type {String} - */ - p.src = null; - - /** - * The maximum number of instances in this channel. -1 indicates no limit - * #property max - * @type {Number} - */ - p.max = null; - - /** - * The default value to set for max, if it isn't passed in. Also used if -1 is passed. - * #property maxDefault - * @type {Number} - * @default 100 - * @since 0.4.0 - */ - p.maxDefault = 100; - - /** - * The current number of active instances. - * #property length - * @type {Number} - */ - p.length = 0; - - /** - * Initialize the channel. - * #method init - * @param {String} src The source of the channel - * @param {Number} max The maximum number of instances in the channel - * @protected - */ - p.init = function (src, max) { - this.src = src; - this.max = max || this.maxDefault; - if (this.max == -1) {this.max = this.maxDefault;} - this._instances = []; - }; - - /** - * Get an instance by index. - * #method get - * @param {Number} index The index to return. - * @return {AbstractSoundInstance} The AbstractSoundInstance at a specific instance. - */ - p._get = function (index) { - return this._instances[index]; - }; - - /** - * Add a new instance to the channel. - * #method add - * @param {AbstractSoundInstance} instance The instance to add. - * @return {Boolean} The success of the method call. If the channel is full, it will return false. - */ - p._add = function (instance, interrupt) { - if (!this._getSlot(interrupt, instance)) {return false;} - this._instances.push(instance); - this.length++; - return true; - }; - - /** - * Remove an instance from the channel, either when it has finished playing, or it has been interrupted. - * #method remove - * @param {AbstractSoundInstance} instance The instance to remove - * @return {Boolean} The success of the remove call. If the instance is not found in this channel, it will - * return false. - */ - p._remove = function (instance) { - var index = createjs.indexOf(this._instances, instance); - if (index == -1) {return false;} - this._instances.splice(index, 1); - this.length--; - return true; - }; - - /** - * Stop playback and remove all instances from the channel. Usually in response to a delete call. - * #method removeAll - */ - p._removeAll = function () { - // Note that stop() removes the item from the list - for (var i=this.length-1; i>=0; i--) { - this._instances[i].stop(); - } - }; - - /** - * Get an available slot depending on interrupt value and if slots are available. - * #method getSlot - * @param {String} interrupt The interrupt value to use. - * @param {AbstractSoundInstance} instance The sound instance that will go in the channel if successful. - * @return {Boolean} Determines if there is an available slot. Depending on the interrupt mode, if there are no slots, - * an existing AbstractSoundInstance may be interrupted. If there are no slots, this method returns false. - */ - p._getSlot = function (interrupt, instance) { - var target, replacement; - - if (interrupt != Sound.INTERRUPT_NONE) { - // First replacement candidate - replacement = this._get(0); - if (replacement == null) { - return true; - } - } - - for (var i = 0, l = this.max; i < l; i++) { - target = this._get(i); - - // Available Space - if (target == null) { - return true; - } - - // Audio is complete or not playing - if (target.playState == Sound.PLAY_FINISHED || - target.playState == Sound.PLAY_INTERRUPTED || - target.playState == Sound.PLAY_FAILED) { - replacement = target; - break; - } - - if (interrupt == Sound.INTERRUPT_NONE) { - continue; - } - - // Audio is a better candidate than the current target, according to playhead - if ((interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) || - (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) { - replacement = target; - } - } - - if (replacement != null) { - replacement._interrupt(); - this._remove(replacement); - return true; - } - return false; - }; - - p.toString = function () { - return "[Sound SoundChannel]"; - }; - // do not add SoundChannel to namespace - -}()); - -//############################################################################## -// AbstractSoundInstance.js -//############################################################################## - -this.createjs = this.createjs || {}; - -/** - * A AbstractSoundInstance is created when any calls to the Sound API method {{#crossLink "Sound/play"}}{{/crossLink}} or - * {{#crossLink "Sound/createInstance"}}{{/crossLink}} are made. The AbstractSoundInstance is returned by the active plugin - * for control by the user. - * - *

        Example

        - * - * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3"); - * - * A number of additional parameters provide a quick way to determine how a sound is played. Please see the Sound - * API method {{#crossLink "Sound/play"}}{{/crossLink}} for a list of arguments. - * - * Once a AbstractSoundInstance is created, a reference can be stored that can be used to control the audio directly through - * the AbstractSoundInstance. If the reference is not stored, the AbstractSoundInstance will play out its audio (and any loops), and - * is then de-referenced from the {{#crossLink "Sound"}}{{/crossLink}} class so that it can be cleaned up. If audio - * playback has completed, a simple call to the {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} instance method - * will rebuild the references the Sound class need to control it. - * - * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3", {loop:2}); - * myInstance.on("loop", handleLoop); - * function handleLoop(event) { - * myInstance.volume = myInstance.volume * 0.5; - * } - * - * Events are dispatched from the instance to notify when the sound has completed, looped, or when playback fails - * - * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3"); - * myInstance.on("complete", handleComplete); - * myInstance.on("loop", handleLoop); - * myInstance.on("failed", handleFailed); - * - * - * @class AbstractSoundInstance - * @param {String} src The path to and file name of the sound. - * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds. - * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds. - * @param {Object} playbackResource Any resource needed by plugin to support audio playback. - * @extends EventDispatcher - * @constructor - */ - -(function () { - "use strict"; - - -// Constructor: - var AbstractSoundInstance = function (src, startTime, duration, playbackResource) { - this.EventDispatcher_constructor(); - - - // public properties: - /** - * The source of the sound. - * @property src - * @type {String} - * @default null - */ - this.src = src; - - /** - * The unique ID of the instance. This is set by {{#crossLink "Sound"}}{{/crossLink}}. - * @property uniqueId - * @type {String} | Number - * @default -1 - */ - this.uniqueId = -1; - - /** - * The play state of the sound. Play states are defined as constants on {{#crossLink "Sound"}}{{/crossLink}}. - * @property playState - * @type {String} - * @default null - */ - this.playState = null; - - /** - * A Timeout created by {{#crossLink "Sound"}}{{/crossLink}} when this AbstractSoundInstance is played with a delay. - * This allows AbstractSoundInstance to remove the delay if stop, pause, or cleanup are called before playback begins. - * @property delayTimeoutId - * @type {timeoutVariable} - * @default null - * @protected - * @since 0.4.0 - */ - this.delayTimeoutId = null; - // TODO consider moving delay into AbstractSoundInstance so it can be handled by plugins - - - // private properties - // Getter / Setter Properties - // OJR TODO find original reason that we didn't use defined functions. I think it was performance related - /** - * The volume of the sound, between 0 and 1. - * - * The actual output volume of a sound can be calculated using: - * myInstance.volume * createjs.Sound.getVolume(); - * - * @property volume - * @type {Number} - * @default 1 - */ - this._volume = 1; - Object.defineProperty(this, "volume", { - get: this.getVolume, - set: this.setVolume - }); - - /** - * The pan of the sound, between -1 (left) and 1 (right). Note that pan is not supported by HTML Audio. - * - *
        Note in WebAudioPlugin this only gives us the "x" value of what is actually 3D audio. - * - * @property pan - * @type {Number} - * @default 0 - */ - this._pan = 0; - Object.defineProperty(this, "pan", { - get: this.getPan, - set: this.setPan - }); - - /** - * Audio sprite property used to determine the starting offset. - * @property startTime - * @type {Number} - * @default 0 - * @since 0.6.1 - */ - this._startTime = Math.max(0, startTime || 0); - Object.defineProperty(this, "startTime", { - get: this.getStartTime, - set: this.setStartTime - }); - - /** - * Sets or gets the length of the audio clip, value is in milliseconds. - * - * @property duration - * @type {Number} - * @default 0 - * @since 0.6.0 - */ - this._duration = Math.max(0, duration || 0); - Object.defineProperty(this, "duration", { - get: this.getDuration, - set: this.setDuration - }); - - /** - * Object that holds plugin specific resource need for audio playback. - * This is set internally by the plugin. For example, WebAudioPlugin will set an array buffer, - * HTMLAudioPlugin will set a tag, FlashAudioPlugin will set a flash reference. - * - * @property playbackResource - * @type {Object} - * @default null - */ - this._playbackResource = null; - Object.defineProperty(this, "playbackResource", { - get: this.getPlaybackResource, - set: this.setPlaybackResource - }); - if(playbackResource !== false && playbackResource !== true) { this.setPlaybackResource(playbackResource); } - - /** - * The position of the playhead in milliseconds. This can be set while a sound is playing, paused, or stopped. - * - * @property position - * @type {Number} - * @default 0 - * @since 0.6.0 - */ - this._position = 0; - Object.defineProperty(this, "position", { - get: this.getPosition, - set: this.setPosition - }); - - /** - * The number of play loops remaining. Negative values will loop infinitely. - * - * @property loop - * @type {Number} - * @default 0 - * @public - * @since 0.6.0 - */ - this._loop = 0; - Object.defineProperty(this, "loop", { - get: this.getLoop, - set: this.setLoop - }); - - /** - * Mutes or unmutes the current audio instance. - * - * @property muted - * @type {Boolean} - * @default false - * @since 0.6.0 - */ - this._muted = false; - Object.defineProperty(this, "muted", { - get: this.getMuted, - set: this.setMuted - }); - - /** - * Pauses or resumes the current audio instance. - * - * @property paused - * @type {Boolean} - */ - this._paused = false; - Object.defineProperty(this, "paused", { - get: this.getPaused, - set: this.setPaused - }); - - - // Events - /** - * The event that is fired when playback has started successfully. - * @event succeeded - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.4.0 - */ - - /** - * The event that is fired when playback is interrupted. This happens when another sound with the same - * src property is played using an interrupt value that causes this instance to stop playing. - * @event interrupted - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.4.0 - */ - - /** - * The event that is fired when playback has failed. This happens when there are too many channels with the same - * src property already playing (and the interrupt value doesn't cause an interrupt of another instance), or - * the sound could not be played, perhaps due to a 404 error. - * @event failed - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.4.0 - */ - - /** - * The event that is fired when a sound has completed playing but has loops remaining. - * @event loop - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.4.0 - */ - - /** - * The event that is fired when playback completes. This means that the sound has finished playing in its - * entirety, including its loop iterations. - * @event complete - * @param {Object} target The object that dispatched the event. - * @param {String} type The event type. - * @since 0.4.0 - */ - }; - - var p = createjs.extend(AbstractSoundInstance, createjs.EventDispatcher); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// Public Methods: - /** - * Play an instance. This method is intended to be called on SoundInstances that already exist (created - * with the Sound API {{#crossLink "Sound/createInstance"}}{{/crossLink}} or {{#crossLink "Sound/play"}}{{/crossLink}}). - * - *

        Example

        - * - * var myInstance = createjs.Sound.createInstance(mySrc); - * myInstance.play({interrupt:createjs.Sound.INTERRUPT_ANY, loop:2, pan:0.5}); - * - * Note that if this sound is already playing, this call will still set the passed in parameters. - - * Parameters Deprecated
        - * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}. - * - * @method play - * @param {String | Object} [interrupt="none"|options] This parameter will be renamed playProps in the next release.
        - * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name, - * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample). - *
        OR
        - * Deprecated How to interrupt any currently playing instances of audio with the same source, - * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE - * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}. - * @param {Number} [delay=0] Deprecated The amount of time to delay the start of audio playback, in milliseconds. - * @param {Number} [offset=0] Deprecated The offset from the start of the audio to begin playback, in milliseconds. - * @param {Number} [loop=0] Deprecated How many times the audio loops when it reaches the end of playback. The default is 0 (no - * loops), and -1 can be used for infinite playback. - * @param {Number} [volume=1] Deprecated The volume of the sound, between 0 and 1. Note that the master volume is applied - * against the individual volume. - * @param {Number} [pan=0] Deprecated The left-right pan of the sound (if supported), between -1 (left) and 1 (right). - * Note that pan is not supported for HTML Audio. - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - */ - p.play = function (interrupt, delay, offset, loop, volume, pan) { - var playProps; - if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) { - playProps = createjs.PlayPropsConfig.create(interrupt); - } else { - playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan}); - } - - if (this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this.applyPlayProps(playProps); - if (this._paused) { this.setPaused(false); } - return; - } - this._cleanUp(); - createjs.Sound._playInstance(this, playProps); // make this an event dispatch?? - return this; - }; - - /** - * Stop playback of the instance. Stopped sounds will reset their position to 0, and calls to {{#crossLink "AbstractSoundInstance/resume"}}{{/crossLink}} - * will fail. To start playback again, call {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}. - * - * If you don't want to lose your position use yourSoundInstance.paused = true instead. {{#crossLink "AbstractSoundInstance/paused"}}{{/crossLink}}. - * - *

        Example

        - * - * myInstance.stop(); - * - * @method stop - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - */ - p.stop = function () { - this._position = 0; - this._paused = false; - this._handleStop(); - this._cleanUp(); - this.playState = createjs.Sound.PLAY_FINISHED; - return this; - }; - - /** - * Remove all external references and resources from AbstractSoundInstance. Note this is irreversible and AbstractSoundInstance will no longer work - * @method destroy - * @since 0.6.0 - */ - p.destroy = function() { - this._cleanUp(); - this.src = null; - this.playbackResource = null; - - this.removeAllEventListeners(); - }; - - /** - * Takes an PlayPropsConfig or Object with the same properties and sets them on this instance. - * @method applyPlayProps - * @param {PlayPropsConfig | Object} playProps A PlayPropsConfig or object containing the same properties. - * @since 0.6.1 - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - */ - p.applyPlayProps = function(playProps) { - if (playProps.offset != null) { this.setPosition(playProps.offset) } - if (playProps.loop != null) { this.setLoop(playProps.loop); } - if (playProps.volume != null) { this.setVolume(playProps.volume); } - if (playProps.pan != null) { this.setPan(playProps.pan); } - if (playProps.startTime != null) { - this.setStartTime(playProps.startTime); - this.setDuration(playProps.duration); - } - return this; - }; - - p.toString = function () { - return "[AbstractSoundInstance]"; - }; - -// get/set methods that allow support for IE8 - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property, - * - * @deprecated - * @method getPaused - * @returns {boolean} If the instance is currently paused - * @since 0.6.0 - */ - p.getPaused = function() { - return this._paused; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setPaused - * @param {boolean} value - * @since 0.6.0 - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - */ - p.setPaused = function (value) { - if ((value !== true && value !== false) || this._paused == value) {return;} - if (value == true && this.playState != createjs.Sound.PLAY_SUCCEEDED) {return;} - this._paused = value; - if(value) { - this._pause(); - } else { - this._resume(); - } - clearTimeout(this.delayTimeoutId); - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setVolume - * @param {Number} value The volume to set, between 0 and 1. - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - */ - p.setVolume = function (value) { - if (value == this._volume) { return this; } - this._volume = Math.max(0, Math.min(1, value)); - if (!this._muted) { - this._updateVolume(); - } - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getVolume - * @return {Number} The current volume of the sound instance. - */ - p.getVolume = function () { - return this._volume; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setMuted - * @param {Boolean} value If the sound should be muted. - * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls. - * @since 0.6.0 - */ - p.setMuted = function (value) { - if (value !== true && value !== false) {return;} - this._muted = value; - this._updateVolume(); - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getMuted - * @return {Boolean} If the sound is muted. - * @since 0.6.0 - */ - p.getMuted = function () { - return this._muted; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setPan - * @param {Number} value The pan value, between -1 (left) and 1 (right). - * @return {AbstractSoundInstance} Returns reference to itself for chaining calls - */ - p.setPan = function (value) { - if(value == this._pan) { return this; } - this._pan = Math.max(-1, Math.min(1, value)); - this._updatePan(); - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getPan - * @return {Number} The value of the pan, between -1 (left) and 1 (right). - */ - p.getPan = function () { - return this._pan; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getPosition - * @return {Number} The position of the playhead in the sound, in milliseconds. - */ - p.getPosition = function () { - if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._position = this._calculateCurrentPosition(); - } - return this._position; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setPosition - * @param {Number} value The position to place the playhead, in milliseconds. - * @return {AbstractSoundInstance} Returns reference to itself for chaining calls - */ - p.setPosition = function (value) { - this._position = Math.max(0, value); - if (this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._updatePosition(); - } - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getStartTime - * @return {Number} The startTime of the sound instance in milliseconds. - */ - p.getStartTime = function () { - return this._startTime; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setStartTime - * @param {number} value The new startTime time in milli seconds. - * @return {AbstractSoundInstance} Returns reference to itself for chaining calls - */ - p.setStartTime = function (value) { - if (value == this._startTime) { return this; } - this._startTime = Math.max(0, value || 0); - this._updateStartTime(); - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getDuration - * @return {Number} The duration of the sound instance in milliseconds. - */ - p.getDuration = function () { - return this._duration; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setDuration - * @param {number} value The new duration time in milli seconds. - * @return {AbstractSoundInstance} Returns reference to itself for chaining calls - * @since 0.6.0 - */ - p.setDuration = function (value) { - if (value == this._duration) { return this; } - this._duration = Math.max(0, value || 0); - this._updateDuration(); - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setPlayback - * @param {Object} value The new playback resource. - * @return {AbstractSoundInstance} Returns reference to itself for chaining calls - * @since 0.6.0 - **/ - p.setPlaybackResource = function (value) { - this._playbackResource = value; - if (this._duration == 0) { this._setDurationFromSource(); } - return this; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method setPlayback - * @param {Object} value The new playback resource. - * @return {Object} playback resource used for playing audio - * @since 0.6.0 - **/ - p.getPlaybackResource = function () { - return this._playbackResource; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property - * - * @deprecated - * @method getLoop - * @return {number} - * @since 0.6.0 - **/ - p.getLoop = function () { - return this._loop; - }; - - /** - * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property, - * - * @deprecated - * @method setLoop - * @param {number} value The number of times to loop after play. - * @since 0.6.0 - */ - p.setLoop = function (value) { - if(this._playbackResource != null) { - // remove looping - if (this._loop != 0 && value == 0) { - this._removeLooping(value); - } - // add looping - else if (this._loop == 0 && value != 0) { - this._addLooping(value); - } - } - this._loop = value; - }; - - -// Private Methods: - /** - * A helper method that dispatches all events for AbstractSoundInstance. - * @method _sendEvent - * @param {String} type The event type - * @protected - */ - p._sendEvent = function (type) { - var event = new createjs.Event(type); - this.dispatchEvent(event); - }; - - /** - * Clean up the instance. Remove references and clean up any additional properties such as timers. - * @method _cleanUp - * @protected - */ - p._cleanUp = function () { - clearTimeout(this.delayTimeoutId); // clear timeout that plays delayed sound - this._handleCleanUp(); - this._paused = false; - - createjs.Sound._playFinished(this); // TODO change to an event - }; - - /** - * The sound has been interrupted. - * @method _interrupt - * @protected - */ - p._interrupt = function () { - this._cleanUp(); - this.playState = createjs.Sound.PLAY_INTERRUPTED; - this._sendEvent("interrupted"); - }; - - /** - * Called by the Sound class when the audio is ready to play (delay has completed). Starts sound playing if the - * src is loaded, otherwise playback will fail. - * @method _beginPlaying - * @param {PlayPropsConfig} playProps A PlayPropsConfig object. - * @return {Boolean} If playback succeeded. - * @protected - */ - // OJR FlashAudioSoundInstance overwrites - p._beginPlaying = function (playProps) { - this.setPosition(playProps.offset); - this.setLoop(playProps.loop); - this.setVolume(playProps.volume); - this.setPan(playProps.pan); - if (playProps.startTime != null) { - this.setStartTime(playProps.startTime); - this.setDuration(playProps.duration); - } - - if (this._playbackResource != null && this._position < this._duration) { - this._paused = false; - this._handleSoundReady(); - this.playState = createjs.Sound.PLAY_SUCCEEDED; - this._sendEvent("succeeded"); - return true; - } else { - this._playFailed(); - return false; - } - }; - - /** - * Play has failed, which can happen for a variety of reasons. - * Cleans up instance and dispatches failed event - * @method _playFailed - * @private - */ - p._playFailed = function () { - this._cleanUp(); - this.playState = createjs.Sound.PLAY_FAILED; - this._sendEvent("failed"); - }; - - /** - * Audio has finished playing. Manually loop it if required. - * @method _handleSoundComplete - * @param event - * @protected - */ - p._handleSoundComplete = function (event) { - this._position = 0; // have to set this as it can be set by pause during playback - - if (this._loop != 0) { - this._loop--; // NOTE this introduces a theoretical limit on loops = float max size x 2 - 1 - this._handleLoop(); - this._sendEvent("loop"); - return; - } - - this._cleanUp(); - this.playState = createjs.Sound.PLAY_FINISHED; - this._sendEvent("complete"); - }; - -// Plugin specific code - /** - * Handles starting playback when the sound is ready for playing. - * @method _handleSoundReady - * @protected - */ - p._handleSoundReady = function () { - // plugin specific code - }; - - /** - * Internal function used to update the volume based on the instance volume, master volume, instance mute value, - * and master mute value. - * @method _updateVolume - * @protected - */ - p._updateVolume = function () { - // plugin specific code - }; - - /** - * Internal function used to update the pan - * @method _updatePan - * @protected - * @since 0.6.0 - */ - p._updatePan = function () { - // plugin specific code - }; - - /** - * Internal function used to update the startTime of the audio. - * @method _updateStartTime - * @protected - * @since 0.6.1 - */ - p._updateStartTime = function () { - // plugin specific code - }; - - /** - * Internal function used to update the duration of the audio. - * @method _updateDuration - * @protected - * @since 0.6.0 - */ - p._updateDuration = function () { - // plugin specific code - }; - - /** - * Internal function used to get the duration of the audio from the source we'll be playing. - * @method _updateDuration - * @protected - * @since 0.6.0 - */ - p._setDurationFromSource = function () { - // plugin specific code - }; - - /** - * Internal function that calculates the current position of the playhead and sets this._position to that value - * @method _calculateCurrentPosition - * @protected - * @since 0.6.0 - */ - p._calculateCurrentPosition = function () { - // plugin specific code that sets this.position - }; - - /** - * Internal function used to update the position of the playhead. - * @method _updatePosition - * @protected - * @since 0.6.0 - */ - p._updatePosition = function () { - // plugin specific code - }; - - /** - * Internal function called when looping is removed during playback. - * @method _removeLooping - * @param {number} value The number of times to loop after play. - * @protected - * @since 0.6.0 - */ - p._removeLooping = function (value) { - // plugin specific code - }; - - /** - * Internal function called when looping is added during playback. - * @method _addLooping - * @param {number} value The number of times to loop after play. - * @protected - * @since 0.6.0 - */ - p._addLooping = function (value) { - // plugin specific code - }; - - /** - * Internal function called when pausing playback - * @method _pause - * @protected - * @since 0.6.0 - */ - p._pause = function () { - // plugin specific code - }; - - /** - * Internal function called when resuming playback - * @method _resume - * @protected - * @since 0.6.0 - */ - p._resume = function () { - // plugin specific code - }; - - /** - * Internal function called when stopping playback - * @method _handleStop - * @protected - * @since 0.6.0 - */ - p._handleStop = function() { - // plugin specific code - }; - - /** - * Internal function called when AbstractSoundInstance is being cleaned up - * @method _handleCleanUp - * @protected - * @since 0.6.0 - */ - p._handleCleanUp = function() { - // plugin specific code - }; - - /** - * Internal function called when AbstractSoundInstance has played to end and is looping - * @method _handleLoop - * @protected - * @since 0.6.0 - */ - p._handleLoop = function () { - // plugin specific code - }; - - createjs.AbstractSoundInstance = createjs.promote(AbstractSoundInstance, "EventDispatcher"); - createjs.DefaultSoundInstance = createjs.AbstractSoundInstance; // used when no plugin is supported -}()); - -//############################################################################## -// AbstractPlugin.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - -// constructor: - /** - * A default plugin class used as a base for all other plugins. - * @class AbstractPlugin - * @constructor - * @since 0.6.0 - */ - - var AbstractPlugin = function () { - // private properties: - /** - * The capabilities of the plugin. - * method and is used internally. - * @property _capabilities - * @type {Object} - * @default null - * @protected - * @static - */ - this._capabilities = null; - - /** - * Object hash indexed by the source URI of all created loaders, used to properly destroy them if sources are removed. - * @type {Object} - * @protected - */ - this._loaders = {}; - - /** - * Object hash indexed by the source URI of each file to indicate if an audio source has begun loading, - * is currently loading, or has completed loading. Can be used to store non boolean data after loading - * is complete (for example arrayBuffers for web audio). - * @property _audioSources - * @type {Object} - * @protected - */ - this._audioSources = {}; - - /** - * Object hash indexed by the source URI of all created SoundInstances, updates the playbackResource if it loads after they are created, - * and properly destroy them if sources are removed - * @type {Object} - * @protected - */ - this._soundInstances = {}; - - /** - * The internal master volume value of the plugin. - * @property _volume - * @type {Number} - * @default 1 - * @protected - */ - this._volume = 1; - - /** - * A reference to a loader class used by a plugin that must be set. - * @type {Object} - * @protected - */ - this._loaderClass; - - /** - * A reference to an AbstractSoundInstance class used by a plugin that must be set. - * @type {Object} - * @protected; - */ - this._soundInstanceClass; - }; - var p = AbstractPlugin.prototype; - - /** - * REMOVED. Removed in favor of using `MySuperClass_constructor`. - * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}} - * for details. - * - * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance. - * - * @method initialize - * @protected - * @deprecated - */ - // p.initialize = function() {}; // searchable for devs wondering where it is. - - -// Static Properties: -// NOTE THESE PROPERTIES NEED TO BE ADDED TO EACH PLUGIN - /** - * The capabilities of the plugin. This is generated via the _generateCapabilities method and is used internally. - * @property _capabilities - * @type {Object} - * @default null - * @protected - * @static - */ - AbstractPlugin._capabilities = null; - - /** - * Determine if the plugin can be used in the current browser/OS. - * @method isSupported - * @return {Boolean} If the plugin can be initialized. - * @static - */ - AbstractPlugin.isSupported = function () { - return true; - }; - - -// public methods: - /** - * Pre-register a sound for preloading and setup. This is called by {{#crossLink "Sound"}}{{/crossLink}}. - * Note all plugins provide a Loader instance, which PreloadJS - * can use to assist with preloading. - * @method register - * @param {String} loadItem An Object containing the source of the audio - * Note that not every plugin will manage this value. - * @return {Object} A result object, containing a "tag" for preloading purposes. - */ - p.register = function (loadItem) { - var loader = this._loaders[loadItem.src]; - if(loader && !loader.canceled) {return this._loaders[loadItem.src];} // already loading/loaded this, so don't load twice - // OJR potential issue that we won't be firing loaded event, might need to trigger if this is already loaded? - this._audioSources[loadItem.src] = true; - this._soundInstances[loadItem.src] = []; - loader = new this._loaderClass(loadItem); - loader.on("complete", this._handlePreloadComplete, this); - this._loaders[loadItem.src] = loader; - return loader; - }; - - // note sound calls register before calling preload - /** - * Internally preload a sound. - * @method preload - * @param {Loader} loader The sound URI to load. - */ - p.preload = function (loader) { - loader.on("error", this._handlePreloadError, this); - loader.load(); - }; - - /** - * Checks if preloading has started for a specific source. If the source is found, we can assume it is loading, - * or has already finished loading. - * @method isPreloadStarted - * @param {String} src The sound URI to check. - * @return {Boolean} - */ - p.isPreloadStarted = function (src) { - return (this._audioSources[src] != null); - }; - - /** - * Checks if preloading has finished for a specific source. - * @method isPreloadComplete - * @param {String} src The sound URI to load. - * @return {Boolean} - */ - p.isPreloadComplete = function (src) { - return (!(this._audioSources[src] == null || this._audioSources[src] == true)); - }; - - /** - * Remove a sound added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload. - * @method removeSound - * @param {String} src The sound URI to unload. - */ - p.removeSound = function (src) { - if (!this._soundInstances[src]) { return; } - for (var i = this._soundInstances[src].length; i--; ) { - var item = this._soundInstances[src][i]; - item.destroy(); - } - delete(this._soundInstances[src]); - delete(this._audioSources[src]); - if(this._loaders[src]) { this._loaders[src].destroy(); } - delete(this._loaders[src]); - }; - - /** - * Remove all sounds added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload. - * @method removeAllSounds - * @param {String} src The sound URI to unload. - */ - p.removeAllSounds = function () { - for(var key in this._audioSources) { - this.removeSound(key); - } - }; - - /** - * Create a sound instance. If the sound has not been preloaded, it is internally preloaded here. - * @method create - * @param {String} src The sound source to use. - * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds. - * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds. - * @return {AbstractSoundInstance} A sound instance for playback and control. - */ - p.create = function (src, startTime, duration) { - if (!this.isPreloadStarted(src)) { - this.preload(this.register(src)); - } - var si = new this._soundInstanceClass(src, startTime, duration, this._audioSources[src]); - this._soundInstances[src].push(si); - return si; - }; - - // if a plugin does not support volume and mute, it should set these to null - /** - * Set the master volume of the plugin, which affects all SoundInstances. - * @method setVolume - * @param {Number} value The volume to set, between 0 and 1. - * @return {Boolean} If the plugin processes the setVolume call (true). The Sound class will affect all the - * instances manually otherwise. - */ - p.setVolume = function (value) { - this._volume = value; - this._updateVolume(); - return true; - }; - - /** - * Get the master volume of the plugin, which affects all SoundInstances. - * @method getVolume - * @return {Number} The volume level, between 0 and 1. - */ - p.getVolume = function () { - return this._volume; - }; - - /** - * Mute all sounds via the plugin. - * @method setMute - * @param {Boolean} value If all sound should be muted or not. Note that plugin-level muting just looks up - * the mute value of Sound {{#crossLink "Sound/getMute"}}{{/crossLink}}, so this property is not used here. - * @return {Boolean} If the mute call succeeds. - */ - p.setMute = function (value) { - this._updateVolume(); - return true; - }; - - // plugins should overwrite this method - p.toString = function () { - return "[AbstractPlugin]"; - }; - - -// private methods: - /** - * Handles internal preload completion. - * @method _handlePreloadComplete - * @protected - */ - p._handlePreloadComplete = function (event) { - var src = event.target.getItem().src; - this._audioSources[src] = event.result; - for (var i = 0, l = this._soundInstances[src].length; i < l; i++) { - var item = this._soundInstances[src][i]; - item.setPlaybackResource(this._audioSources[src]); - // ToDo consider adding play call here if playstate == playfailed - } - }; - - /** - * Handles internal preload erros - * @method _handlePreloadError - * @param event - * @protected - */ - p._handlePreloadError = function(event) { - //delete(this._audioSources[src]); - }; - - /** - * Set the gain value for master audio. Should not be called externally. - * @method _updateVolume - * @protected - */ - p._updateVolume = function () { - // Plugin Specific code - }; - - createjs.AbstractPlugin = AbstractPlugin; -}()); - -//############################################################################## -// WebAudioLoader.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * Loader provides a mechanism to preload Web Audio content via PreloadJS or internally. Instances are returned to - * the preloader, and the load method is called when the asset needs to be requested. - * - * @class WebAudioLoader - * @param {String} loadItem The item to be loaded - * @extends XHRRequest - * @protected - */ - function Loader(loadItem) { - this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.SOUND); - - }; - var p = createjs.extend(Loader, createjs.AbstractLoader); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - - /** - * web audio context required for decoding audio - * @property context - * @type {AudioContext} - * @static - */ - Loader.context = null; - - -// public methods - p.toString = function () { - return "[WebAudioLoader]"; - }; - - -// private methods - p._createRequest = function() { - this._request = new createjs.XHRRequest(this._item, false); - this._request.setResponseType("arraybuffer"); - }; - - p._sendComplete = function (event) { - // OJR we leave this wrapped in Loader because we need to reference src and the handler only receives a single argument, the decodedAudio - Loader.context.decodeAudioData(this._rawResult, - createjs.proxy(this._handleAudioDecoded, this), - createjs.proxy(this._sendError, this)); - }; - - - /** - * The audio has been decoded. - * @method handleAudioDecoded - * @param decoded - * @protected - */ - p._handleAudioDecoded = function (decodedAudio) { - this._result = decodedAudio; - this.AbstractLoader__sendComplete(); - }; - - createjs.WebAudioLoader = createjs.promote(Loader, "AbstractLoader"); -}()); - -//############################################################################## -// WebAudioSoundInstance.js -//############################################################################## - -this.createjs = this.createjs || {}; - -/** - * WebAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by - * {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. - * - * WebAudioSoundInstance exposes audioNodes for advanced users. - * - * @param {String} src The path to and file name of the sound. - * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds. - * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds. - * @param {Object} playbackResource Any resource needed by plugin to support audio playback. - * @class WebAudioSoundInstance - * @extends AbstractSoundInstance - * @constructor - */ -(function () { - "use strict"; - - function WebAudioSoundInstance(src, startTime, duration, playbackResource) { - this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource); - - -// public properties - /** - * NOTE this is only intended for use by advanced users. - *
        GainNode for controlling WebAudioSoundInstance volume. Connected to the {{#crossLink "WebAudioSoundInstance/destinationNode:property"}}{{/crossLink}}. - * @property gainNode - * @type {AudioGainNode} - * @since 0.4.0 - * - */ - this.gainNode = s.context.createGain(); - - /** - * NOTE this is only intended for use by advanced users. - *
        A panNode allowing left and right audio channel panning only. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}. - * @property panNode - * @type {AudioPannerNode} - * @since 0.4.0 - */ - this.panNode = s.context.createPanner(); - this.panNode.panningModel = s._panningModel; - this.panNode.connect(this.gainNode); - this._updatePan(); - - /** - * NOTE this is only intended for use by advanced users. - *
        sourceNode is the audio source. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/panNode:property"}}{{/crossLink}}. - * @property sourceNode - * @type {AudioNode} - * @since 0.4.0 - * - */ - this.sourceNode = null; - - -// private properties - /** - * Timeout that is created internally to handle sound playing to completion. - * Stored so we can remove it when stop, pause, or cleanup are called - * @property _soundCompleteTimeout - * @type {timeoutVariable} - * @default null - * @protected - * @since 0.4.0 - */ - this._soundCompleteTimeout = null; - - /** - * NOTE this is only intended for use by very advanced users. - * _sourceNodeNext is the audio source for the next loop, inserted in a look ahead approach to allow for smooth - * looping. Connected to {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}. - * @property _sourceNodeNext - * @type {AudioNode} - * @default null - * @protected - * @since 0.4.1 - * - */ - this._sourceNodeNext = null; - - /** - * Time audio started playback, in seconds. Used to handle set position, get position, and resuming from paused. - * @property _playbackStartTime - * @type {Number} - * @default 0 - * @protected - * @since 0.4.0 - */ - this._playbackStartTime = 0; - - // Proxies, make removing listeners easier. - this._endedHandler = createjs.proxy(this._handleSoundComplete, this); - }; - var p = createjs.extend(WebAudioSoundInstance, createjs.AbstractSoundInstance); - var s = WebAudioSoundInstance; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - - /** - * Note this is only intended for use by advanced users. - *
        Audio context used to create nodes. This is and needs to be the same context used by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. - * @property context - * @type {AudioContext} - * @static - * @since 0.6.0 - */ - s.context = null; - - /** - * Note this is only intended for use by advanced users. - *
        The scratch buffer that will be assigned to the buffer property of a source node on close. - * This is and should be the same scratch buffer referenced by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. - * @property _scratchBuffer - * @type {AudioBufferSourceNode} - * @static - */ - s._scratchBuffer = null; - - /** - * Note this is only intended for use by advanced users. - *
        Audio node from WebAudioPlugin that sequences to context.destination - * @property destinationNode - * @type {AudioNode} - * @static - * @since 0.6.0 - */ - s.destinationNode = null; - - /** - * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation. - * @property _panningModel - * @type {Number / String} - * @protected - * @static - * @since 0.6.0 - */ - s._panningModel = "equalpower"; - - -// Public methods - p.destroy = function() { - this.AbstractSoundInstance_destroy(); - - this.panNode.disconnect(0); - this.panNode = null; - this.gainNode.disconnect(0); - this.gainNode = null; - }; - - p.toString = function () { - return "[WebAudioSoundInstance]"; - }; - - -// Private Methods - p._updatePan = function() { - this.panNode.setPosition(this._pan, 0, -0.5); - // z need to be -0.5 otherwise the sound only plays in left, right, or center - }; - - p._removeLooping = function(value) { - this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - }; - - p._addLooping = function(value) { - if (this.playState != createjs.Sound.PLAY_SUCCEEDED) { return; } - this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0); - }; - - p._setDurationFromSource = function () { - this._duration = this.playbackResource.duration * 1000; - }; - - p._handleCleanUp = function () { - if (this.sourceNode && this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this.sourceNode = this._cleanUpAudioNode(this.sourceNode); - this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - } - - if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);} - // OJR there appears to be a bug that this doesn't always work in webkit (Chrome and Safari). According to the documentation, this should work. - - clearTimeout(this._soundCompleteTimeout); - - this._playbackStartTime = 0; // This is used by getPosition - }; - - /** - * Turn off and disconnect an audioNode, then set reference to null to release it for garbage collection - * @method _cleanUpAudioNode - * @param audioNode - * @return {audioNode} - * @protected - * @since 0.4.1 - */ - p._cleanUpAudioNode = function(audioNode) { - if(audioNode) { - audioNode.stop(0); - audioNode.disconnect(0); - // necessary to prevent leak on iOS Safari 7-9. will throw in almost all other - // browser implementations. - try { audioNode.buffer = s._scratchBuffer; } catch(e) {} - audioNode = null; - } - return audioNode; - }; - - p._handleSoundReady = function (event) { - this.gainNode.connect(s.destinationNode); // this line can cause a memory leak. Nodes need to be disconnected from the audioDestination or any sequence that leads to it. - - var dur = this._duration * 0.001; - var pos = this._position * 0.001; - if (pos > dur) {pos = dur;} - this.sourceNode = this._createAndPlayAudioNode((s.context.currentTime - dur), pos); - this._playbackStartTime = this.sourceNode.startTime - pos; - - this._soundCompleteTimeout = setTimeout(this._endedHandler, (dur - pos) * 1000); - - if(this._loop != 0) { - this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0); - } - }; - - /** - * Creates an audio node using the current src and context, connects it to the gain node, and starts playback. - * @method _createAndPlayAudioNode - * @param {Number} startTime The time to add this to the web audio context, in seconds. - * @param {Number} offset The amount of time into the src audio to start playback, in seconds. - * @return {audioNode} - * @protected - * @since 0.4.1 - */ - p._createAndPlayAudioNode = function(startTime, offset) { - var audioNode = s.context.createBufferSource(); - audioNode.buffer = this.playbackResource; - audioNode.connect(this.panNode); - var dur = this._duration * 0.001; - audioNode.startTime = startTime + dur; - audioNode.start(audioNode.startTime, offset+(this._startTime*0.001), dur - offset); - return audioNode; - }; - - p._pause = function () { - this._position = (s.context.currentTime - this._playbackStartTime) * 1000; // * 1000 to give milliseconds, lets us restart at same point - this.sourceNode = this._cleanUpAudioNode(this.sourceNode); - this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - - if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);} - - clearTimeout(this._soundCompleteTimeout); - }; - - p._resume = function () { - this._handleSoundReady(); - }; - - /* - p._handleStop = function () { - // web audio does not need to do anything extra - }; - */ - - p._updateVolume = function () { - var newVolume = this._muted ? 0 : this._volume; - if (newVolume != this.gainNode.gain.value) { - this.gainNode.gain.value = newVolume; - } - }; - - p._calculateCurrentPosition = function () { - return ((s.context.currentTime - this._playbackStartTime) * 1000); // pos in seconds * 1000 to give milliseconds - }; - - p._updatePosition = function () { - this.sourceNode = this._cleanUpAudioNode(this.sourceNode); - this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext); - clearTimeout(this._soundCompleteTimeout); - - if (!this._paused) {this._handleSoundReady();} - }; - - // OJR we are using a look ahead approach to ensure smooth looping. - // We add _sourceNodeNext to the audio context so that it starts playing even if this callback is delayed. - // This technique is described here: http://www.html5rocks.com/en/tutorials/audio/scheduling/ - // NOTE the cost of this is that our audio loop may not always match the loop event timing precisely. - p._handleLoop = function () { - this._cleanUpAudioNode(this.sourceNode); - this.sourceNode = this._sourceNodeNext; - this._playbackStartTime = this.sourceNode.startTime; - this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0); - this._soundCompleteTimeout = setTimeout(this._endedHandler, this._duration); - }; - - p._updateDuration = function () { - if(this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._pause(); - this._resume(); - } - }; - - createjs.WebAudioSoundInstance = createjs.promote(WebAudioSoundInstance, "AbstractSoundInstance"); -}()); - -//############################################################################## -// WebAudioPlugin.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - - "use strict"; - - /** - * Play sounds using Web Audio in the browser. The WebAudioPlugin is currently the default plugin, and will be used - * anywhere that it is supported. To change plugin priority, check out the Sound API - * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} method. - - *

        Known Browser and OS issues for Web Audio

        - * Firefox 25 - *
      • - * mp3 audio files do not load properly on all windows machines, reported here. - *
        For this reason it is recommended to pass another FireFox-supported type (i.e. ogg) as the default - * extension, until this bug is resolved - *
      • - * - * Webkit (Chrome and Safari) - *
      • - * AudioNode.disconnect does not always seem to work. This can cause the file size to grow over time if you - * are playing a lot of audio files. - *
      • - * - * iOS 6 limitations - *
          - *
        • - * Sound is initially muted and will only unmute through play being called inside a user initiated event - * (touch/click). Please read the mobile playback notes in the the {{#crossLink "Sound"}}{{/crossLink}} - * class for a full overview of the limitations, and how to get around them. - *
        • - *
        • - * A bug exists that will distort un-cached audio when a video element is present in the DOM. You can avoid - * this bug by ensuring the audio and video audio share the same sample rate. - *
        • - *
        - * @class WebAudioPlugin - * @extends AbstractPlugin - * @constructor - * @since 0.4.0 - */ - function WebAudioPlugin() { - this.AbstractPlugin_constructor(); - - -// Private Properties - /** - * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation. - * @property _panningModel - * @type {Number / String} - * @protected - */ - this._panningModel = s._panningModel;; - - /** - * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin - * need to be created within this context. - * @property context - * @type {AudioContext} - */ - this.context = s.context; - - /** - * A DynamicsCompressorNode, which is used to improve sound quality and prevent audio distortion. - * It is connected to context.destination. - * - * Can be accessed by advanced users through createjs.Sound.activePlugin.dynamicsCompressorNode. - * @property dynamicsCompressorNode - * @type {AudioNode} - */ - this.dynamicsCompressorNode = this.context.createDynamicsCompressor(); - this.dynamicsCompressorNode.connect(this.context.destination); - - /** - * A GainNode for controlling master volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}. - * - * Can be accessed by advanced users through createjs.Sound.activePlugin.gainNode. - * @property gainNode - * @type {AudioGainNode} - */ - this.gainNode = this.context.createGain(); - this.gainNode.connect(this.dynamicsCompressorNode); - createjs.WebAudioSoundInstance.destinationNode = this.gainNode; - - this._capabilities = s._capabilities; - - this._loaderClass = createjs.WebAudioLoader; - this._soundInstanceClass = createjs.WebAudioSoundInstance; - - this._addPropsToClasses(); - } - var p = createjs.extend(WebAudioPlugin, createjs.AbstractPlugin); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// Static Properties - var s = WebAudioPlugin; - /** - * The capabilities of the plugin. This is generated via the {{#crossLink "WebAudioPlugin/_generateCapabilities:method"}}{{/crossLink}} - * method and is used internally. - * @property _capabilities - * @type {Object} - * @default null - * @protected - * @static - */ - s._capabilities = null; - - /** - * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation. - * @property _panningModel - * @type {Number / String} - * @protected - * @static - */ - s._panningModel = "equalpower"; - - /** - * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin - * need to be created within this context. - * - * Advanced users can set this to an existing context, but must do so before they call - * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}. - * - * @property context - * @type {AudioContext} - * @static - */ - s.context = null; - - /** - * The scratch buffer that will be assigned to the buffer property of a source node on close. - * Works around an iOS Safari bug: https://github.com/CreateJS/SoundJS/issues/102 - * - * Advanced users can set this to an existing source node, but must do so before they call - * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}. - * - * @property _scratchBuffer - * @type {AudioBuffer} - * @protected - * @static - */ - s._scratchBuffer = null; - - /** - * Indicated whether audio on iOS has been unlocked, which requires a touchend/mousedown event that plays an - * empty sound. - * @property _unlocked - * @type {boolean} - * @since 0.6.2 - * @private - */ - s._unlocked = false; - - -// Static Public Methods - /** - * Determine if the plugin can be used in the current browser/OS. - * @method isSupported - * @return {Boolean} If the plugin can be initialized. - * @static - */ - s.isSupported = function () { - // check if this is some kind of mobile device, Web Audio works with local protocol under PhoneGap and it is unlikely someone is trying to run a local file - var isMobilePhoneGap = createjs.BrowserDetect.isIOS || createjs.BrowserDetect.isAndroid || createjs.BrowserDetect.isBlackberry; - // OJR isMobile may be redundant with _isFileXHRSupported available. Consider removing. - if (location.protocol == "file:" && !isMobilePhoneGap && !this._isFileXHRSupported()) { return false; } // Web Audio requires XHR, which is not usually available locally - s._generateCapabilities(); - if (s.context == null) {return false;} - return true; - }; - - /** - * Plays an empty sound in the web audio context. This is used to enable web audio on iOS devices, as they - * require the first sound to be played inside of a user initiated event (touch/click). This is called when - * {{#crossLink "WebAudioPlugin"}}{{/crossLink}} is initialized (by Sound {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}} - * for example). - * - *

        Example

        - * - * function handleTouch(event) { - * createjs.WebAudioPlugin.playEmptySound(); - * } - * - * @method playEmptySound - * @static - * @since 0.4.1 - */ - s.playEmptySound = function() { - if (s.context == null) {return;} - var source = s.context.createBufferSource(); - source.buffer = s._scratchBuffer; - source.connect(s.context.destination); - source.start(0, 0, 0); - }; - - -// Static Private Methods - /** - * Determine if XHR is supported, which is necessary for web audio. - * @method _isFileXHRSupported - * @return {Boolean} If XHR is supported. - * @since 0.4.2 - * @protected - * @static - */ - s._isFileXHRSupported = function() { - // it's much easier to detect when something goes wrong, so let's start optimistically - var supported = true; - - var xhr = new XMLHttpRequest(); - try { - xhr.open("GET", "WebAudioPluginTest.fail", false); // loading non-existant file triggers 404 only if it could load (synchronous call) - } catch (error) { - // catch errors in cases where the onerror is passed by - supported = false; - return supported; - } - xhr.onerror = function() { supported = false; }; // cause irrelevant - // with security turned off, we can get empty success results, which is actually a failed read (status code 0?) - xhr.onload = function() { supported = this.status == 404 || (this.status == 200 || (this.status == 0 && this.response != "")); }; - try { - xhr.send(); - } catch (error) { - // catch errors in cases where the onerror is passed by - supported = false; - } - - return supported; - }; - - /** - * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}} - * method for an overview of plugin capabilities. - * @method _generateCapabilities - * @static - * @protected - */ - s._generateCapabilities = function () { - if (s._capabilities != null) {return;} - // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section - var t = document.createElement("audio"); - if (t.canPlayType == null) {return null;} - - if (s.context == null) { - if (window.AudioContext) { - s.context = new AudioContext(); - } else if (window.webkitAudioContext) { - s.context = new webkitAudioContext(); - } else { - return null; - } - } - if (s._scratchBuffer == null) { - s._scratchBuffer = s.context.createBuffer(1, 1, 22050); - } - - s._compatibilitySetUp(); - - // Listen for document level clicks to unlock WebAudio on iOS. See the _unlock method. - if ("ontouchstart" in window && s.context.state != "running") { - s._unlock(); // When played inside of a touch event, this will enable audio on iOS immediately. - document.addEventListener("mousedown", s._unlock, true); - document.addEventListener("touchend", s._unlock, true); - } - - - s._capabilities = { - panning:true, - volume:true, - tracks:-1 - }; - - // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS - var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS; - var extensionMap = createjs.Sound.EXTENSION_MAP; - for (var i = 0, l = supportedExtensions.length; i < l; i++) { - var ext = supportedExtensions[i]; - var playType = extensionMap[ext] || ext; - s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != ""); - } // OJR another way to do this might be canPlayType:"m4a", codex: mp4 - - // 0=no output, 1=mono, 2=stereo, 4=surround, 6=5.1 surround. - // See http://www.w3.org/TR/webaudio/#AudioChannelSplitter for more details on channels. - if (s.context.destination.numberOfChannels < 2) { - s._capabilities.panning = false; - } - }; - - /** - * Set up compatibility if only deprecated web audio calls are supported. - * See http://www.w3.org/TR/webaudio/#DeprecationNotes - * Needed so we can support new browsers that don't support deprecated calls (Firefox) as well as old browsers that - * don't support new calls. - * - * @method _compatibilitySetUp - * @static - * @protected - * @since 0.4.2 - */ - s._compatibilitySetUp = function() { - s._panningModel = "equalpower"; - //assume that if one new call is supported, they all are - if (s.context.createGain) { return; } - - // simple name change, functionality the same - s.context.createGain = s.context.createGainNode; - - // source node, add to prototype - var audioNode = s.context.createBufferSource(); - audioNode.__proto__.start = audioNode.__proto__.noteGrainOn; // note that noteGrainOn requires all 3 parameters - audioNode.__proto__.stop = audioNode.__proto__.noteOff; - - // panningModel - s._panningModel = 0; - }; - - /** - * Try to unlock audio on iOS. This is triggered from either WebAudio plugin setup (which will work if inside of - * a `mousedown` or `touchend` event stack), or the first document touchend/mousedown event. If it fails (touchend - * will fail if the user presses for too long, indicating a scroll event instead of a click event. - * - * Note that earlier versions of iOS supported `touchstart` for this, but iOS9 removed this functionality. Adding - * a `touchstart` event to support older platforms may preclude a `mousedown` even from getting fired on iOS9, so we - * stick with `mousedown` and `touchend`. - * @method _unlock - * @since 0.6.2 - * @private - */ - s._unlock = function() { - if (s._unlocked) { return; } - s.playEmptySound(); - if (s.context.state == "running") { - document.removeEventListener("mousedown", s._unlock, true); - document.removeEventListener("touchend", s._unlock, true); - s._unlocked = true; - } - }; - - -// Public Methods - p.toString = function () { - return "[WebAudioPlugin]"; - }; - - -// Private Methods - /** - * Set up needed properties on supported classes WebAudioSoundInstance and WebAudioLoader. - * @method _addPropsToClasses - * @static - * @protected - * @since 0.6.0 - */ - p._addPropsToClasses = function() { - var c = this._soundInstanceClass; - c.context = this.context; - c._scratchBuffer = s._scratchBuffer; - c.destinationNode = this.gainNode; - c._panningModel = this._panningModel; - - this._loaderClass.context = this.context; - }; - - - /** - * Set the gain value for master audio. Should not be called externally. - * @method _updateVolume - * @protected - */ - p._updateVolume = function () { - var newVolume = createjs.Sound._masterMute ? 0 : this._volume; - if (newVolume != this.gainNode.gain.value) { - this.gainNode.gain.value = newVolume; - } - }; - - createjs.WebAudioPlugin = createjs.promote(WebAudioPlugin, "AbstractPlugin"); -}()); - -//############################################################################## -// HTMLAudioTagPool.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * HTMLAudioTagPool is an object pool for HTMLAudio tag instances. - * @class HTMLAudioTagPool - * @param {String} src The source of the channel. - * @protected - */ - function HTMLAudioTagPool() { - throw "HTMLAudioTagPool cannot be instantiated"; - } - - var s = HTMLAudioTagPool; - -// Static Properties - /** - * A hash lookup of each base audio tag, indexed by the audio source. - * @property _tags - * @type {{}} - * @static - * @protected - */ - s._tags = {}; - - /** - * An object pool for html audio tags - * @property _tagPool - * @type {TagPool} - * @static - * @protected - */ - s._tagPool = new TagPool(); - - /** - * A hash lookup of if a base audio tag is available, indexed by the audio source - * @property _tagsUsed - * @type {{}} - * @protected - * @static - */ - s._tagUsed = {}; - -// Static Methods - /** - * Get an audio tag with the given source. - * @method get - * @param {String} src The source file used by the audio tag. - * @static - */ - s.get = function (src) { - var t = s._tags[src]; - if (t == null) { - // create new base tag - t = s._tags[src] = s._tagPool.get(); - t.src = src; - } else { - // get base or pool - if (s._tagUsed[src]) { - t = s._tagPool.get(); - t.src = src; - } else { - s._tagUsed[src] = true; - } - } - return t; - }; - - /** - * Return an audio tag to the pool. - * @method set - * @param {String} src The source file used by the audio tag. - * @param {HTMLElement} tag Audio tag to set. - * @static - */ - s.set = function (src, tag) { - // check if this is base, if yes set boolean if not return to pool - if(tag == s._tags[src]) { - s._tagUsed[src] = false; - } else { - s._tagPool.set(tag); - } - }; - - /** - * Delete stored tag reference and return them to pool. Note that if the tag reference does not exist, this will fail. - * @method remove - * @param {String} src The source for the tag - * @return {Boolean} If the TagPool was deleted. - * @static - */ - s.remove = function (src) { - var tag = s._tags[src]; - if (tag == null) {return false;} - s._tagPool.set(tag); - delete(s._tags[src]); - delete(s._tagUsed[src]); - return true; - }; - - /** - * Gets the duration of the src audio in milliseconds - * @method getDuration - * @param {String} src The source file used by the audio tag. - * @return {Number} Duration of src in milliseconds - * @static - */ - s.getDuration= function (src) { - var t = s._tags[src]; - if (t == null || !t.duration) {return 0;} // OJR duration is NaN if loading has not completed - return t.duration * 1000; - }; - - createjs.HTMLAudioTagPool = HTMLAudioTagPool; - - -// ************************************************************************************************************ - /** - * The TagPool is an object pool for HTMLAudio tag instances. - * #class TagPool - * @param {String} src The source of the channel. - * @protected - */ - function TagPool(src) { - -// Public Properties - /** - * A list of all available tags in the pool. - * #property tags - * @type {Array} - * @protected - */ - this._tags = []; - }; - - var p = TagPool.prototype; - p.constructor = TagPool; - - -// Public Methods - /** - * Get an HTMLAudioElement for immediate playback. This takes it out of the pool. - * #method get - * @return {HTMLAudioElement} An HTML audio tag. - */ - p.get = function () { - var tag; - if (this._tags.length == 0) { - tag = this._createTag(); - } else { - tag = this._tags.pop(); - } - if (tag.parentNode == null) {document.body.appendChild(tag);} - return tag; - }; - - /** - * Put an HTMLAudioElement back in the pool for use. - * #method set - * @param {HTMLAudioElement} tag HTML audio tag - */ - p.set = function (tag) { - // OJR this first step seems unnecessary - var index = createjs.indexOf(this._tags, tag); - if (index == -1) { - this._tags.src = null; - this._tags.push(tag); - } - }; - - p.toString = function () { - return "[TagPool]"; - }; - - -// Private Methods - /** - * Create an HTML audio tag. - * #method _createTag - * @param {String} src The source file to set for the audio tag. - * @return {HTMLElement} Returns an HTML audio tag. - * @protected - */ - p._createTag = function () { - var tag = document.createElement("audio"); - tag.autoplay = false; - tag.preload = "none"; - //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works. - return tag; - }; - -}()); - -//############################################################################## -// HTMLAudioSoundInstance.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - "use strict"; - - /** - * HTMLAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by - * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}. - * - * @param {String} src The path to and file name of the sound. - * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds. - * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds. - * @param {Object} playbackResource Any resource needed by plugin to support audio playback. - * @class HTMLAudioSoundInstance - * @extends AbstractSoundInstance - * @constructor - */ - function HTMLAudioSoundInstance(src, startTime, duration, playbackResource) { - this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource); - - -// Private Properties - this._audioSpriteStopTime = null; - this._delayTimeoutId = null; - - // Proxies, make removing listeners easier. - this._endedHandler = createjs.proxy(this._handleSoundComplete, this); - this._readyHandler = createjs.proxy(this._handleTagReady, this); - this._stalledHandler = createjs.proxy(this._playFailed, this); - this._audioSpriteEndHandler = createjs.proxy(this._handleAudioSpriteLoop, this); - this._loopHandler = createjs.proxy(this._handleSoundComplete, this); - - if (duration) { - this._audioSpriteStopTime = (startTime + duration) * 0.001; - } else { - this._duration = createjs.HTMLAudioTagPool.getDuration(this.src); - } - } - var p = createjs.extend(HTMLAudioSoundInstance, createjs.AbstractSoundInstance); - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// Public Methods - /** - * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master volume. - * undoc'd because it is not meant to be used outside of Sound - * #method setMasterVolume - * @param value - */ - p.setMasterVolume = function (value) { - this._updateVolume(); - }; - - /** - * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master mute. - * undoc'd because it is not meant to be used outside of Sound - * #method setMasterMute - * @param value - */ - p.setMasterMute = function (isMuted) { - this._updateVolume(); - }; - - p.toString = function () { - return "[HTMLAudioSoundInstance]"; - }; - -//Private Methods - p._removeLooping = function() { - if(this._playbackResource == null) {return;} - this._playbackResource.loop = false; - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - }; - - p._addLooping = function() { - if(this._playbackResource == null || this._audioSpriteStopTime) {return;} - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - this._playbackResource.loop = true; - }; - - p._handleCleanUp = function () { - var tag = this._playbackResource; - if (tag != null) { - tag.pause(); - tag.loop = false; - tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false); - tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false); - tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false); - tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - tag.removeEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false); - - try { - tag.currentTime = this._startTime; - } catch (e) { - } // Reset Position - createjs.HTMLAudioTagPool.set(this.src, tag); - this._playbackResource = null; - } - }; - - p._beginPlaying = function (playProps) { - this._playbackResource = createjs.HTMLAudioTagPool.get(this.src); - return this.AbstractSoundInstance__beginPlaying(playProps); - }; - - p._handleSoundReady = function (event) { - if (this._playbackResource.readyState !== 4) { - var tag = this._playbackResource; - tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false); - tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false); - tag.preload = "auto"; // This is necessary for Firefox, as it won't ever "load" until this is set. - tag.load(); - return; - } - - this._updateVolume(); - this._playbackResource.currentTime = (this._startTime + this._position) * 0.001; - if (this._audioSpriteStopTime) { - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false); - } else { - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false); - if(this._loop != 0) { - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - this._playbackResource.loop = true; - } - } - - this._playbackResource.play(); - }; - - /** - * Used to handle when a tag is not ready for immediate playback when it is returned from the HTMLAudioTagPool. - * @method _handleTagReady - * @param event - * @protected - */ - p._handleTagReady = function (event) { - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false); - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false); - - this._handleSoundReady(); - }; - - p._pause = function () { - this._playbackResource.pause(); - }; - - p._resume = function () { - this._playbackResource.play(); - }; - - p._updateVolume = function () { - if (this._playbackResource != null) { - var newVolume = (this._muted || createjs.Sound._masterMute) ? 0 : this._volume * createjs.Sound._masterVolume; - if (newVolume != this._playbackResource.volume) {this._playbackResource.volume = newVolume;} - } - }; - - p._calculateCurrentPosition = function() { - return (this._playbackResource.currentTime * 1000) - this._startTime; - }; - - p._updatePosition = function() { - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false); - try { - this._playbackResource.currentTime = (this._position + this._startTime) * 0.001; - } catch (error) { // Out of range - this._handleSetPositionSeek(null); - } - }; - - /** - * Used to enable setting position, as we need to wait for that seek to be done before we add back our loop handling seek listener - * @method _handleSetPositionSeek - * @param event - * @protected - */ - p._handleSetPositionSeek = function(event) { - if (this._playbackResource == null) { return; } - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false); - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - }; - - /** - * Timer used to loop audio sprites. - * NOTE because of the inaccuracies in the timeupdate event (15 - 250ms) and in setting the tag to the desired timed - * (up to 300ms), it is strongly recommended not to loop audio sprites with HTML Audio if smooth looping is desired - * - * @method _handleAudioSpriteLoop - * @param event - * @private - */ - p._handleAudioSpriteLoop = function (event) { - if(this._playbackResource.currentTime <= this._audioSpriteStopTime) {return;} - this._playbackResource.pause(); - if(this._loop == 0) { - this._handleSoundComplete(null); - } else { - this._position = 0; - this._loop--; - this._playbackResource.currentTime = this._startTime * 0.001; - if(!this._paused) {this._playbackResource.play();} - this._sendEvent("loop"); - } - }; - - // NOTE with this approach audio will loop as reliably as the browser allows - // but we could end up sending the loop event after next loop playback begins - p._handleLoop = function (event) { - if(this._loop == 0) { - this._playbackResource.loop = false; - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false); - } - }; - - p._updateStartTime = function () { - this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001; - - if(this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false); - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false); - } - }; - - p._updateDuration = function () { - this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001; - - if(this.playState == createjs.Sound.PLAY_SUCCEEDED) { - this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false); - this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false); - } - }; - - p._setDurationFromSource = function () { - this._duration = createjs.HTMLAudioTagPool.getDuration(this.src); - this._playbackResource = null; - }; - - createjs.HTMLAudioSoundInstance = createjs.promote(HTMLAudioSoundInstance, "AbstractSoundInstance"); -}()); - -//############################################################################## -// HTMLAudioPlugin.js -//############################################################################## - -this.createjs = this.createjs || {}; - -(function () { - - "use strict"; - - /** - * Play sounds using HTML <audio> tags in the browser. This plugin is the second priority plugin installed - * by default, after the {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. For older browsers that do not support html - * audio, include and install the {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}. - * - *

        Known Browser and OS issues for HTML Audio

        - * All browsers
        - * Testing has shown in all browsers there is a limit to how many audio tag instances you are allowed. If you exceed - * this limit, you can expect to see unpredictable results. Please use {{#crossLink "Sound.MAX_INSTANCES"}}{{/crossLink}} as - * a guide to how many total audio tags you can safely use in all browsers. This issue is primarily limited to IE9. - * - * IE html limitations
        - *
        • There is a delay in applying volume changes to tags that occurs once playback is started. So if you have - * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of - * when or how you apply the volume change, as the tag seems to need to play to apply it.
        • - *
        • MP3 encoding will not always work for audio tags if it's not default. We've found default encoding with - * 64kbps works.
        • - *
        • Occasionally very short samples will get cut off.
        • - *
        • There is a limit to how many audio tags you can load or play at once, which appears to be determined by - * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate. - * Note that audio sprites can be used as a solution to this issue.
        - * - * Safari limitations
        - *
        • Safari requires Quicktime to be installed for audio playback.
        - * - * iOS 6 limitations
        - *
        • can only have one <audio> tag
        • - *
        • can not preload or autoplay the audio
        • - *
        • can not cache the audio
        • - *
        • can not play the audio except inside a user initiated event.
        • - *
        • Note it is recommended to use {{#crossLink "WebAudioPlugin"}}{{/crossLink}} for iOS (6+)
        • - *
        • audio sprites can be used to mitigate some of these issues and are strongly recommended on iOS
        • - *
        - * - * Android Native Browser limitations
        - *
        • We have no control over audio volume. Only the user can set volume on their device.
        • - *
        • We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use a delay.
        - * Android Chrome 26.0.1410.58 specific limitations
        - *
        • Can only play 1 sound at a time.
        • - *
        • Sound is not cached.
        • - *
        • Sound can only be loaded in a user initiated touch/click event.
        • - *
        • There is a delay before a sound is played, presumably while the src is loaded.
        • - *
        - * - * See {{#crossLink "Sound"}}{{/crossLink}} for general notes on known issues. - * - * @class HTMLAudioPlugin - * @extends AbstractPlugin - * @constructor - */ - function HTMLAudioPlugin() { - this.AbstractPlugin_constructor(); - - - // Public Properties - /** - * This is no longer needed as we are now using object pooling for tags. - * - * NOTE this property only exists as a limitation of HTML audio. - * @property defaultNumChannels - * @type {Number} - * @default 2 - * @since 0.4.0 - * @deprecated - */ - this.defaultNumChannels = 2; - - this._capabilities = s._capabilities; - - this._loaderClass = createjs.SoundLoader; - this._soundInstanceClass = createjs.HTMLAudioSoundInstance; - } - - var p = createjs.extend(HTMLAudioPlugin, createjs.AbstractPlugin); - var s = HTMLAudioPlugin; - - // TODO: deprecated - // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details. - - -// Static Properties - /** - * The maximum number of instances that can be loaded or played. This is a browser limitation, primarily limited to IE9. - * The actual number varies from browser to browser (and is largely hardware dependant), but this is a safe estimate. - * Audio sprites work around this limitation. - * @property MAX_INSTANCES - * @type {Number} - * @default 30 - * @static - */ - s.MAX_INSTANCES = 30; - - /** - * Event constant for the "canPlayThrough" event for cleaner code. - * @property _AUDIO_READY - * @type {String} - * @default canplaythrough - * @static - * @protected - */ - s._AUDIO_READY = "canplaythrough"; - - /** - * Event constant for the "ended" event for cleaner code. - * @property _AUDIO_ENDED - * @type {String} - * @default ended - * @static - * @protected - */ - s._AUDIO_ENDED = "ended"; - - /** - * Event constant for the "seeked" event for cleaner code. We utilize this event for maintaining loop events. - * @property _AUDIO_SEEKED - * @type {String} - * @default seeked - * @static - * @protected - */ - s._AUDIO_SEEKED = "seeked"; - - /** - * Event constant for the "stalled" event for cleaner code. - * @property _AUDIO_STALLED - * @type {String} - * @default stalled - * @static - * @protected - */ - s._AUDIO_STALLED = "stalled"; - - /** - * Event constant for the "timeupdate" event for cleaner code. Utilized for looping audio sprites. - * This event callsback ever 15 to 250ms and can be dropped by the browser for performance. - * @property _TIME_UPDATE - * @type {String} - * @default timeupdate - * @static - * @protected - */ - s._TIME_UPDATE = "timeupdate"; - - /** - * The capabilities of the plugin. This is generated via the {{#crossLink "HTMLAudioPlugin/_generateCapabilities"}}{{/crossLink}} - * method. Please see the Sound {{#crossLink "Sound/getCapabilities"}}{{/crossLink}} method for an overview of all - * of the available properties. - * @property _capabilities - * @type {Object} - * @protected - * @static - */ - s._capabilities = null; - - -// Static Methods - /** - * Determine if the plugin can be used in the current browser/OS. Note that HTML audio is available in most modern - * browsers, but is disabled in iOS because of its limitations. - * @method isSupported - * @return {Boolean} If the plugin can be initialized. - * @static - */ - s.isSupported = function () { - s._generateCapabilities(); - return (s._capabilities != null); - }; - - /** - * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}} - * method for an overview of plugin capabilities. - * @method _generateCapabilities - * @static - * @protected - */ - s._generateCapabilities = function () { - if (s._capabilities != null) {return;} - var t = document.createElement("audio"); - if (t.canPlayType == null) {return null;} - - s._capabilities = { - panning:false, - volume:true, - tracks:-1 - }; - - // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS - var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS; - var extensionMap = createjs.Sound.EXTENSION_MAP; - for (var i = 0, l = supportedExtensions.length; i < l; i++) { - var ext = supportedExtensions[i]; - var playType = extensionMap[ext] || ext; - s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != ""); - } // OJR another way to do this might be canPlayType:"m4a", codex: mp4 - }; - - -// public methods - p.register = function (loadItem) { - var tag = createjs.HTMLAudioTagPool.get(loadItem.src); - var loader = this.AbstractPlugin_register(loadItem); - loader.setTag(tag); - - return loader; - }; - - p.removeSound = function (src) { - this.AbstractPlugin_removeSound(src); - createjs.HTMLAudioTagPool.remove(src); - }; - - p.create = function (src, startTime, duration) { - var si = this.AbstractPlugin_create(src, startTime, duration); - si.setPlaybackResource(null); - return si; - }; - - p.toString = function () { - return "[HTMLAudioPlugin]"; - }; - - // plugin does not support these - p.setVolume = p.getVolume = p.setMute = null; - - - createjs.HTMLAudioPlugin = createjs.promote(HTMLAudioPlugin, "AbstractPlugin"); -}()); \ No newline at end of file diff --git a/bomberman/frontend/src/main/webapp/sound/bomb.mp3 b/bomberman/frontend/src/main/webapp/sound/bomb.mp3 deleted file mode 100644 index e419cb6f43..0000000000 Binary files a/bomberman/frontend/src/main/webapp/sound/bomb.mp3 and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/sound/bomb.ogg b/bomberman/frontend/src/main/webapp/sound/bomb.ogg deleted file mode 100644 index 59912972df..0000000000 Binary files a/bomberman/frontend/src/main/webapp/sound/bomb.ogg and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/sound/game.mp3 b/bomberman/frontend/src/main/webapp/sound/game.mp3 deleted file mode 100644 index fe931af90a..0000000000 Binary files a/bomberman/frontend/src/main/webapp/sound/game.mp3 and /dev/null differ diff --git a/bomberman/frontend/src/main/webapp/sound/game.ogg b/bomberman/frontend/src/main/webapp/sound/game.ogg deleted file mode 100644 index 46a859f37f..0000000000 Binary files a/bomberman/frontend/src/main/webapp/sound/game.ogg and /dev/null differ diff --git a/build.gradle b/build.gradle index 77cfa67b56..f3eca85893 100644 --- a/build.gradle +++ b/build.gradle @@ -1,111 +1 @@ -plugins { - id 'org.springframework.boot' version '1.5.8.RELEASE' - id 'com.github.kt3k.coveralls' version '2.6.3' -} - -springBoot { - mainClass = "ru.atom.chat.ChatApplication" -} - -// constants declaration -ext { - jdkVersion = 1.8 - - junitVersion = "4.12" - log4jVersion = "2.7" - jetbrainsAnnotationVersion = "15.0" - okhttpVersion = "3.6.0" - gsonjVersion = "2.7" - postgresVersion = "9.4-1200-jdbc41" - jetbrainsAnnotationVersion = "15.0" - hibernateVersion = "5.1.10.Final" - jolVersion = "0.8" -} - -allprojects { - group = "technoatom" - version = "1.0-SNAPSHOT" - - apply plugin: 'java' - apply plugin: 'checkstyle' - apply plugin: 'jacoco' - - repositories { - mavenCentral() - } - - sourceCompatibility = jdkVersion - targetCompatibility = jdkVersion -} - -subprojects { - if (!project.name.equals('bomberman/frontend')) - apply plugin: 'org.springframework.boot' - - - checkstyle { - ignoreFailures = false - toolVersion = '7.5' - configFile = rootProject.file('config/checkstyle/checkstyle.xml') - } - - tasks.withType(Checkstyle) { - reports { - xml.enabled false - html.destination "$rootProject.buildDir/report/${project.name}.html" - html.stylesheet resources.text.fromFile(rootProject.file('config/checkstyle/checkstyle-custom.xsl')) - } - } - -} - -// common libraries declaration -ext.libraries = [ - spring_boot : [ - "org.springframework.boot:spring-boot-starter-web", - "org.springframework.boot:spring-boot-starter-actuator", - ], - - spring_boot_test : "org.springframework.boot:spring-boot-starter-test", - - spring_boot_websocket: "org.springframework.boot:spring-boot-starter-websocket", - spring_boot_jpa: "org.springframework.boot:spring-boot-starter-data-jpa", - - junit: "junit:junit:$junitVersion", - log4j: [ - "org.apache.logging.log4j:log4j-api:$log4jVersion", - "org.apache.logging.log4j:log4j-core:$log4jVersion" - ], - jetbrainsAnnotations: "org.jetbrains:annotations:$jetbrainsAnnotationVersion", - okhttp: "com.squareup.okhttp3:okhttp:$okhttpVersion", - gson: "com.google.code.gson:gson:$gsonjVersion", - postgres: "org.postgresql:postgresql:$postgresVersion", - hibernate: "org.hibernate:hibernate-core:$hibernateVersion", - jol: "org.openjdk.jol:jol-core:$jolVersion", - jol_samples: "org.openjdk.jol:jol-samples:$jolVersion" -] - -// code coverage settings -jacocoTestReport { - additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs) - sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs) - classDirectories = files(subprojects.sourceSets.main.output) - executionData = files(subprojects.jacocoTestReport.executionData) - onlyIf = { - true - } - - reports { - xml.enabled = true - html.enabled = true - } - doFirst { - executionData = files(executionData.findAll { - it.exists() - }) - } -} - -coveralls { - sourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs).files.absolutePath -} +apply plugin: 'java' \ No newline at end of file diff --git a/homeworks/HW2/.gitignore b/homeworks/HW2/.gitignore index e69de29bb2..fdd31a8416 100644 --- a/homeworks/HW2/.gitignore +++ b/homeworks/HW2/.gitignore @@ -0,0 +1,4 @@ +.gradle +.iml +build +out/ diff --git a/homeworks/HW2/BullsAndCows.iml b/homeworks/HW2/BullsAndCows.iml new file mode 100644 index 0000000000..c90834f2d6 --- /dev/null +++ b/homeworks/HW2/BullsAndCows.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/homeworks/HW2/build.gradle b/homeworks/HW2/build.gradle new file mode 100644 index 0000000000..8ab76d39a9 --- /dev/null +++ b/homeworks/HW2/build.gradle @@ -0,0 +1,42 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * User Manual available at https://docs.gradle.org/5.5.1/userguide/tutorial_java_projects.html + */ + +plugins { + // Apply the java plugin to add support for Java + id 'java' + + // Apply the application plugin to add support for building a CLI application + id 'application' +} + +repositories { + // Use jcenter for resolving dependencies. + // You can declare any Maven/Ivy/file repository here. + jcenter() +} + +dependencies { + // This dependency is used by the application. + implementation 'com.google.guava:guava:27.1-jre' + + // Use JUnit Jupiter API for testing. + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + + // Use JUnit Jupiter Engine for testing. + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' +} + +application { + // Define the main class for the application + mainClassName = 'BullAndCows.App' +} + +test { + // Use junit platform for unit tests + useJUnitPlatform() +} diff --git a/homeworks/HW2/gradle/wrapper/gradle-wrapper.jar b/homeworks/HW2/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..5c2d1cf016 Binary files /dev/null and b/homeworks/HW2/gradle/wrapper/gradle-wrapper.jar differ diff --git a/homeworks/HW2/gradle/wrapper/gradle-wrapper.properties b/homeworks/HW2/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..4b7e1f3d38 --- /dev/null +++ b/homeworks/HW2/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/homeworks/HW2/gradlew b/homeworks/HW2/gradlew new file mode 100644 index 0000000000..8e25e6c19d --- /dev/null +++ b/homeworks/HW2/gradlew @@ -0,0 +1,188 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/homeworks/HW2/gradlew.bat b/homeworks/HW2/gradlew.bat new file mode 100644 index 0000000000..9618d8d960 --- /dev/null +++ b/homeworks/HW2/gradlew.bat @@ -0,0 +1,100 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Bull.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Bull.class new file mode 100644 index 0000000000..f9421235c3 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Bull.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/BullsAndCows.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/BullsAndCows.class new file mode 100644 index 0000000000..e29264660e Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/BullsAndCows.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/CorrectInput.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/CorrectInput.class new file mode 100644 index 0000000000..ed8dcf7948 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/CorrectInput.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Cow.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Cow.class new file mode 100644 index 0000000000..b76e2d8201 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Cow.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Game.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Game.class new file mode 100644 index 0000000000..5aea548dea Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Game.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/GameOver.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/GameOver.class new file mode 100644 index 0000000000..0a3e47d9d6 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/GameOver.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Input.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Input.class new file mode 100644 index 0000000000..1ea99e0a8c Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Input.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Replay.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Replay.class new file mode 100644 index 0000000000..ffa45450b9 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Replay.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Winner.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Winner.class new file mode 100644 index 0000000000..c286a7d811 Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Winner.class differ diff --git a/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Word.class b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Word.class new file mode 100644 index 0000000000..edf8394abc Binary files /dev/null and b/homeworks/HW2/out/production/BullsAndCows/main/java/ru/atom/Word.class differ diff --git a/homeworks/HW2/settings.gradle b/homeworks/HW2/settings.gradle new file mode 100644 index 0000000000..ee19f21b0a --- /dev/null +++ b/homeworks/HW2/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/5.5.1/userguide/multi_project_builds.html + */ + +rootProject.name = 'BullAndCows' diff --git a/homeworks/HW2/src/main/java/ru/atom/Bull.java b/homeworks/HW2/src/main/java/ru/atom/Bull.java new file mode 100644 index 0000000000..18e37bbaf1 --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Bull.java @@ -0,0 +1,18 @@ +package main.java.ru.atom; + +import java.util.ArrayList; + +public class Bull { + private int bull=0; + public void count(ArrayList in,ArrayList word) { + for (int i = 0; i < word.size(); i++) { + if (word.get(i).equals(in.get(i))) { + bull++; + } + } + } + + public int getBull() { + return bull; + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/BullsAndCows.java b/homeworks/HW2/src/main/java/ru/atom/BullsAndCows.java new file mode 100644 index 0000000000..d97ba1161e --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/BullsAndCows.java @@ -0,0 +1,12 @@ +package main.java.ru.atom; + +public class BullsAndCows { + public static void main(String[] args) { + String exit = "y"; + while ("y".equals(exit)) { + Game game = new Game(); + game.game(); + exit=Replay.replay(); + } + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/CorrectInput.java b/homeworks/HW2/src/main/java/ru/atom/CorrectInput.java new file mode 100644 index 0000000000..d05414994a --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/CorrectInput.java @@ -0,0 +1,20 @@ +package main.java.ru.atom; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +public class CorrectInput { + public ArrayList correctInput(int size) { + int length=0; + ArrayList in; + do { + System.out.println("Input " + size + "letter word"); + in=new ArrayList(Input.in().chars() + .mapToObj(e -> (char) e) + .collect(Collectors.toList())); + length = in.size(); + } + while (size != length ); + return in; + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/Cow.java b/homeworks/HW2/src/main/java/ru/atom/Cow.java new file mode 100644 index 0000000000..bb4f8679ec --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Cow.java @@ -0,0 +1,19 @@ +package main.java.ru.atom; + +import java.util.ArrayList; + +public class Cow { + private int cow=0; + public void count(ArrayList in, ArrayList word) { + for (char o : word) { + if (in.contains(o)) { + cow++; + in.set(in.indexOf(o), ' '); + } + } + } + + public int getCow() { + return cow; + } +} \ No newline at end of file diff --git a/homeworks/HW2/src/main/java/ru/atom/Game.java b/homeworks/HW2/src/main/java/ru/atom/Game.java new file mode 100644 index 0000000000..b47ef4fe89 --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Game.java @@ -0,0 +1,34 @@ +package main.java.ru.atom; + +import java.util.ArrayList; +import java.util.stream.Collectors; + +public class Game { + public void game() { + ArrayList word = new ArrayList(Word.cowsAndBulls().chars() + .mapToObj(e -> (char) e) + .collect(Collectors.toList())); + + for (int chance=10; chance > 0; chance--) { + System.out.println("You have " + chance + "chance:"); + + CorrectInput correctInput = new CorrectInput(); + ArrayList in = correctInput.correctInput(word.size()); + + Bull bull = new Bull(); + bull.count(in, word); + + if (bull.getBull()==word.size()) { + System.out.println("You win"); + break; + } + + Cow cow = new Cow(); + cow.count(in, word); + + System.out.println("bulls:" + bull.getBull() + "cows:" + cow.getCow()); + + GameOver.gameOver(word, chance); + } + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/GameOver.java b/homeworks/HW2/src/main/java/ru/atom/GameOver.java new file mode 100644 index 0000000000..001e604f48 --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/GameOver.java @@ -0,0 +1,14 @@ +package main.java.ru.atom; + +import java.util.ArrayList; + +public class GameOver { + public static void gameOver(ArrayList word,int chance) { + if (chance == 1) { + System.out.println("Game over"); + System.out.print("Answer:"); + word.forEach(o -> System.out.print(o)); + System.out.println(""); + } + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/Input.java b/homeworks/HW2/src/main/java/ru/atom/Input.java new file mode 100644 index 0000000000..2be61ec8cd --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Input.java @@ -0,0 +1,10 @@ +package main.java.ru.atom; + +import java.util.Scanner; + +public class Input { + public static String in(){ + Scanner out = new Scanner(System.in); + return out.next(); + } +} \ No newline at end of file diff --git a/homeworks/HW2/src/main/java/ru/atom/Replay.java b/homeworks/HW2/src/main/java/ru/atom/Replay.java new file mode 100644 index 0000000000..77566812cd --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Replay.java @@ -0,0 +1,15 @@ +package main.java.ru.atom; + +public class Replay { + public static String replay () { + String exit="y"; + int i = 0; + while (i == 0) { + System.out.println("do you want replay? y/n"); + exit = Input.in(); + if (exit.equals("y") || exit.equals("n")) + i++; + } + return exit; + } +} diff --git a/homeworks/HW2/src/main/java/ru/atom/Word.java b/homeworks/HW2/src/main/java/ru/atom/Word.java new file mode 100644 index 0000000000..6d71b0eb2b --- /dev/null +++ b/homeworks/HW2/src/main/java/ru/atom/Word.java @@ -0,0 +1,21 @@ +package main.java.ru.atom; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.stream.Stream; + +public class Word { + + private static File file = new File("dictionary.txt"); + + public static String cowsAndBulls() { + String out=""; + try(Stream streamFromFiles = Files.lines(Paths.get("dictionary.txt"))) { + out=streamFromFiles.skip((int) (Math.random() * 52976)).findFirst().get(); + } catch (IOException e) { + e.printStackTrace(); + } + return out; + } +} \ No newline at end of file diff --git a/homeworks/HW2/src/test/java/BullAndCows/AppTest.java b/homeworks/HW2/src/test/java/BullAndCows/AppTest.java new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/homeworks/HW2/src/test/java/BullAndCows/AppTest.java @@ -0,0 +1 @@ + diff --git a/lecture04/gradlew b/lecture04/gradlew index cccdd3d517..af6708ff22 100755 --- a/lecture04/gradlew +++ b/lecture04/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/lecture04/gradlew.bat b/lecture04/gradlew.bat index e95643d6a2..0f8d5937c4 100644 --- a/lecture04/gradlew.bat +++ b/lecture04/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/lecture04/src/main/java/ru/atom/cache/ContactListCache.java b/lecture04/src/main/java/ru/atom/cache/ContactListCache.java index 5770b33eaf..9b975386d2 100644 --- a/lecture04/src/main/java/ru/atom/cache/ContactListCache.java +++ b/lecture04/src/main/java/ru/atom/cache/ContactListCache.java @@ -1,6 +1,5 @@ package ru.atom.cache; - import java.util.List; /** diff --git a/lecture04/src/main/java/ru/atom/chat/client/ChatClient.java b/lecture04/src/main/java/ru/atom/chat/client/ChatClient.java index 18174df197..c14e31d127 100644 --- a/lecture04/src/main/java/ru/atom/chat/client/ChatClient.java +++ b/lecture04/src/main/java/ru/atom/chat/client/ChatClient.java @@ -13,7 +13,7 @@ public class ChatClient { private static final OkHttpClient client = new OkHttpClient(); private static final String PROTOCOL = "http://"; - private static final String HOST = "localhost"; + private static final String HOST = "54.224.37.210"; private static final String PORT = ":8080"; //POST host:port/chat/login?name=my_name @@ -40,11 +40,22 @@ public static Response viewChat() throws IOException { //POST host:port/chat/say?name=my_name //Body: "msg='my_message'" public static Response say(String name, String msg) throws IOException { - throw new UnsupportedOperationException(); + MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded"); + Request request = new Request.Builder() + .post(RequestBody.create(mediaType, "")) + .url(PROTOCOL + HOST + PORT + "/chat/say?name=" + name + "/chat/chat?msg=" + msg) + .build(); + + return client.newCall(request).execute(); } //GET host:port/chat/online public static Response viewOnline() throws IOException { - throw new UnsupportedOperationException(); + Request request = new Request.Builder() + .get() + .url(PROTOCOL + HOST + PORT + "/chat/online") + .addHeader("host", HOST + PORT) + .build(); + return client.newCall(request).execute(); } } \ No newline at end of file diff --git a/lecture05/build.gradle b/lecture05/build.gradle index 84ad1078c1..898ad8eb59 100644 --- a/lecture05/build.gradle +++ b/lecture05/build.gradle @@ -1,26 +1,32 @@ -dependencies { - compile rootProject.libraries.spring_boot - compile rootProject.libraries.log4j - - - testCompile rootProject.libraries.junit - testCompile rootProject.libraries.spring_boot_test +plugins { + id 'org.springframework.boot' version '2.0.0.RELEASE' } -springBoot { - mainClass = "ru.atom.boot.hw.HelloSpringBoot" +repositories { + mavenCentral() } +apply plugin: 'java' +apply plugin: 'checkstyle' -sourceSets { - main { - java { - srcDirs = ['src/main/java'] - } - } - test { - java { - srcDirs = ['src/test/java'] - } - } +dependencies { + // https://mvnrepository.com/artifact/org.slf4j/slf4j-api + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25' + // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl + //compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.10.0' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web + compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator + compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.RELEASE' + + // https://mvnrepository.com/artifact/junit/junit + testCompile group: 'junit', name: 'junit', version: '4.4' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test + testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.0.RELEASE' } + +checkstyle { + ignoreFailures = false + toolVersion = '7.5' + configFile = new File('../config/checkstyle/checkstyle.xml') +} \ No newline at end of file diff --git a/lecture05/gradle/wrapper/gradle-wrapper.jar b/lecture05/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..c44b679acd Binary files /dev/null and b/lecture05/gradle/wrapper/gradle-wrapper.jar differ diff --git a/lecture05/gradle/wrapper/gradle-wrapper.properties b/lecture05/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..f51202dd25 --- /dev/null +++ b/lecture05/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/lecture05/gradlew b/lecture05/gradlew new file mode 100755 index 0000000000..cccdd3d517 --- /dev/null +++ b/lecture05/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/lecture05/gradlew.bat b/lecture05/gradlew.bat new file mode 100644 index 0000000000..e95643d6a2 --- /dev/null +++ b/lecture05/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lecture05/presentation/PITCHME.md b/lecture05/presentation/PITCHME.md index df4e10b3ba..59d28d4289 100644 --- a/lecture05/presentation/PITCHME.md +++ b/lecture05/presentation/PITCHME.md @@ -1,49 +1,46 @@ -#HSLIDE +--- # Java -lecture 5 -## Web server +2018/lecture 5 +## Spring, Threads, Annotations -#HSLIDE + +--- ## Отметьтесь на портале -https://atom.mail.ru/ +https://sphere.mail.ru/ -#HSLIDE +--- ### get ready +[https://github.com/rybalkinsd/atom](https://github.com/rybalkinsd/atom) ```bash > git fetch upstream > git checkout -b lecture05 upstream/lecture05 +> cd lecture05 ``` Refresh gradle project -#HSLIDE -### Поиграем в web-server -Any questions on HTTP? - -**You must understand HTTP!** - - -#HSLIDE +--- ### Agenda 1. Threads 1. Annotations +1. Spring, Spring Boot +1. Inversion of Control, Dependency Injection +1. Beans, ApplicationContext 1. Match-maker -1. HTTP Web Server -1. Spring - -#HSLIDE -### Threads +--- +### Agenda 1. **[Threads]** 1. Annotations +1. Spring, Spring Boot +1. Inversion of Control, Dependency Injection +1. Beans, ApplicationContext 1. Match-maker -1. HTTP Web Server -1. Spring -#HSLIDE +--- ### Threads intro As we go into the land of servers, we face multi-threaded environment. @@ -52,30 +49,30 @@ So this gentle introduction only covers basics that are necessary so far. We will have deeper topics on concurrency further in the course. -#HSLIDE +--- ### Why do we need parallel execution? -#HSLIDE +--- ### Concurrency vs parallelism **Concurrency** - contention on shared resources **Parallelism** is possible without concurrency -#HSLIDE +--- ### Process vs Thread **Process** has dedicated resources (memory) **Threads** share memory space -#HSLIDE +--- ### Process vs Thread process -#HSLIDE +--- ### Operating System role 1. Creates threads (clone syscall) 1. Schedules threads (context switch) @@ -84,7 +81,7 @@ We will have deeper topics on concurrency further in the course. Behaviour of multithreaded program is (inter alia) dependent on OS scheduling -#HSLIDE +--- ### interface Runnable ```java @FunctionalInterface @@ -94,7 +91,7 @@ interface Runnable { ``` -#HSLIDE +--- ### class Thread ```java class Thread implements Runnable { @@ -108,7 +105,7 @@ class Thread implements Runnable { ``` -#HSLIDE +--- ### Start and Run ```java new Thread().start(); @@ -117,11 +114,11 @@ new Thread( runnable ).start(); ``` -#HSLIDE +--- ### Start and Run exception -#HSLIDE +--- ### Thread instantiation @See ru.atom.thread.instantiation and tests @@ -131,8 +128,15 @@ new Thread( runnable ).start(); - Thread::interrupt - Thread::sleep +--- + +### Thread interruption +An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate. +A thread sends an interrupt by invoking interrupt on the Thread object for the thread to be interrupted. For the interrupt mechanism to work correctly, the interrupted thread must support its own interruption. +https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html + +--- -#HSLIDE ### Waiting for thread termination @See ru.atom.thread.join and tests @@ -140,7 +144,7 @@ new Thread( runnable ).start(); - Thread::interrupt -#HSLIDE +--- ### jstack Util to observe java process stack state. @@ -152,7 +156,7 @@ Util to observe java process stack state. > less report.info ``` -#HSLIDE +--- ### Queue Queue is a shared resource in a multi-threaded environment. @@ -174,12 +178,12 @@ interface BlockingQueue implements java.util.Queue { ``` -#HSLIDE +--- ### Queue queue -#HSLIDE +--- ### Your turn @See ru.atom.thread.practice in tests @@ -194,21 +198,22 @@ interface BlockingQueue implements java.util.Queue { 1. Implement missing methods -#HSLIDE -### Annotations +--- +### Agenda 1. Threads 1. **[Annotations]** -1. HTTP Web Server -1. Spring +1. Spring, Spring Boot +1. Inversion of Control, Dependency Injection +1. Beans, ApplicationContext 1. Match-maker -#HSLIDE +--- ### Annotations -What annotations did you see before? +Which annotations did you see before? -#HSLIDE +--- ### Override ```java @Target(ElementType.METHOD) @@ -217,93 +222,37 @@ public @interface Override { } ``` -#HSLIDE +--- ### Reflection API Reflection is an API to find information about classes/fields/methods in application runtime. @See ru.atom.annotation and tests +--- +### Retention policy +Annotation has **Retention policy**, which indicated, whether info about the annotation will be available at runtime +**RetentionPolicy.RUNTIME** guarantees that annotation will be available in **runtime** + -#HSLIDE -### HTTP Web Server +--- +### Agenda 1. Threads 1. Annotations -1. **[HTTP Web Server]** -1. Spring +1. **[Spring, Spring Boot]** +1. Inversion of Control, Dependency Injection +1. Beans, ApplicationContext 1. Match-maker +--- -#HSLIDE -### Web server -**Web server** - is a program that processes HTTP Requests and provide HTTP responses. - -**Web server can be a separate application, like:** -- Apache HTTP Server -- NGINX - -**Can be embedded into application:** -- Jetty -- Embedded Tomcat (**our choice**) - - -#HSLIDE -### Alternative - application servers -Alternatively large projects can use **Application Servers** to manage web application: - - Sun GlassFish - - IBM WebSphere - - RedHat JBoss - -**We will not go this way** - -#HSLIDE -### Servlet container -Basic function of web server - to serve static content (html, css, images) -But most web servers provide some functionality to apply **custom logic on HTTP Request** and return **custom HTTP Response**. - -This can be used to serve dynamic pages or for custom **web application** (that's how we will use it) - -Custom server logic in java can be embedded into **servlet container** (part of web-server, that manages **Servlets**) - - -#HSLIDE -### Servlet -servlet - -#HSLIDE -### Servlet -**Servlet** - is class that handles HTTP Requests. -Java provide low-level **Servlet API** - -#HSLIDE -### Web Server approximate behavior -1. Start -1. Initialize internal servlets -1. Create a "mapping" **(request, /path)** -> handling servlet -1. Apply mapping on incoming request -1. Process **single request in single thread** but in parallel* -1. Process routing of outgoing response +### Matchmaker example - -#HSLIDE -### Modern way -**Servlet API** (a part of java API) - is low-level API -People tend to use high-level frameworks to make web applications -This frameworks use servlet API under the hood +We will use MathMaker application to study basic concepts of Spring -The most famous web framework is **Spring** - - -#HSLIDE -### Spring -1. Threads -1. Annotations -1. HTTP Web Server -1. **[Spring]** -1. Match-maker - +> @see MatchMakerApp -#HSLIDE +--- ### Spring exception is a universal open-source framework, used to develop web applications @@ -311,7 +260,7 @@ https://spring.io/ First version - **2002** -#HSLIDE +--- ### Spring modules It includes a number of modules for different functionality: - Spring MVC for building Web Applications @@ -323,19 +272,7 @@ It includes a number of modules for different functionality: Today we will build web application with **Spring MVC** module -#HSLIDE -### MVC -**MVC (Model-View-Controller)** - popular pattern used to build web apps - - - -#HSLIDE -### Spring MVC -**Spring MVC** - Spring Module that make it easier to build MVC Applications (Like **Django**, **Rails**) -exception - - -#HSLIDE +--- ### Spring Boot Spring is a powerful tool and has a lot of configuration options. **Spring Boot** is a project, that makes working with Spring easier: @@ -349,33 +286,179 @@ First version: **2014** **With Spring Boot our life is much easier :)** -#HSLIDE -### Hello Spring Boot -**@See ru.atom.boot.hw** -All the magic works via **annotations** +--- +### Spring boot distribution +```groovy + // dependencies, necessary for building generic web applicaitons + compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE' + // actuator + compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.RELEASE' +``` + +--- + +### Spring boot actuator +Spring boot actuator - usefool dependency, providing web interface to meta data of application and even interact with it + +**Actuator endpoints:** +https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html +By default most endpoints are disabled. To enable them we need to enable them in **application.properties** -1. Application entry point (HelloSpringBoot) -*@SpringBootApplication* auto-configures spring application -1. Request controller - handles HTTP connections -*@Controller* - let Spring recognize this class -*@RequestMapping("hello")* - this class handles **HTTP Requests** to **/hello** url -*@RequestMapping("world")* - this method handles **HTTP Requests** to **/hello/world** url -*@ResponseBody* method returns result will be the **HTTP response body** +--- +### application.properties +The standard way to configure java application - **application.properties** should appear in classpath +To enable actuator endpoints: +```properties +management.endpoints.web.exposure.include=* +``` +We also can configure actuator and server ports there: +```properties +#server port: +server.port = 8080 +#actuator port: +management.server.port = 7001 +``` -#HSLIDE -### Important notes -These notes are important to understand: -1. HelloController is **Singleton** (by default) - the same instance for all requests -1. Every request runs in **new thread** (actually backed by thread pool) - -Here comes **multi-threading** with **shared memory** (concurrency) - topic for further discussion +--- +### Useful actuator endpoints +**/actuator/health** +overall application status + +**/actuator/mappings** +available mappings + +**/actuator/beans** +all beans in context +--- + +### Agenda +1. Threads +1. Annotations +1. Spring, Spring Boot +1. **[Inversion of Control, Dependency Injection]** +1. Beans, ApplicationContext +1. Match-maker + +--- + +### Inversion of Control +**Principle:** control flow is transferred to external framework +**Why:** loose coupling, easier to develop, easier to test + +--- + +### Dependency Injection +Objects lifecycle is managed by external framework (**IoC container**) +- instantiation +- wiring +- removal + +--- + +### Spring provides IoC container +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans +Interface of **IoC Container** in Spring: +**org.springframework.context.ApplicationContext** +- methods for accessing application components. **ListableBeanFactory** +- methods to load file resources in a generic fashion. **ResourceLoader** +- methods to publish events to registered listeners. **ApplicationEventPublisher** +- methods to resolve messages, supporting internationalization. **MessageSource** + +--- + +### Agenda +1. Threads +1. Annotations +1. Spring, Spring Boot +1. Inversion of Control, Dependency Injection +1. **[Beans, ApplicationContext]** +1. Match-maker + +--- + +### Beans +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-definition +Beans are java objects, that are managed by **IoC Container** + +How to make **bean** out of **POJO** (Plain Old Java Object)? +With bean definition configuration + +--- +### Spring configuration +There are several options for beans configuration: +- XML Description +- Groovy Description +- Annotations + +We will use annotations as this is the cleanest one + +--- + +### Beans Detection +For spring to create and manage beans, we must provide bean definitions +**How to create bean definition with annotations:** +- mark class with **@Configuration**/**@Component**/**@Controller**/**@Service**/**@Repository** or annotations, inheriting their semantics +- mark any method inside such class with **@Bean** (config method) + +--- + +### Beans autowiring +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation +Once we have beans definitions, we can inject those beans with **@Autowired** +Possible targets: +- constructor +- field +- setter method +- config method + +--- + +## ByType and ByName autowiring +```java +@Service +public class MatchMaker implements Runnable { + @Autowired //How do spring know which bean to inject? + private ConnectionQueue connectionQueue; +} +``` +- ByType: it will search the bean with type **ConnectionQueue** or implementation in ApplicationContext +- ByName: with **@Qualifier** annotation we can autowire bean by name +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-qualifiers +--- + +### Bean scopes +https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes +Beans can have different life span depending on requirements. + +**[Common scopes:]** +- Singleton (default) +- Prototype: single bean definition to any number of object instances +- request: single bean definition to the lifecycle of a single HTTP reques +- websocket: single bean definition to the lifecycle of a WebSocket +... + +--- + +### Spring: see documentation +Both basic concepts and details are fully covered in spring documentation. +https://docs.spring.io/spring/docs/current/spring-framework-reference/index.html + +--- + +### Agenda +1. Threads +1. Annotations +1. Spring, Spring Boot +1. Inversion of Control, Dependency Injection +1. Beans, ApplicationContext +1. **[Match-maker]** -#HSLIDE +--- ### Match-maker practice -@See ru.atom.thread.mm and tests +@See ru.atom.mm and tests -#HSLIDE +--- ### Match-maker Our Bomberman is a client-server game. @@ -384,17 +467,17 @@ As a client server game we have Clients or **Connections** Clients want to play. So, we have Games or **GameSessions** -#HSLIDE +--- ### Match-maker mm -#HSLIDE +--- ### Match-making algorithm mmalgo -#HSLIDE +--- ### Match-making algorithm **Assume we have a queue storing connections** @@ -409,7 +492,7 @@ Match-maker is an infinity-loop algorithm with steps - Continue to step #1 -#HSLIDE +--- ### Connection producer We do not have server to get connections for now. We need an instance to emulate client. @@ -418,7 +501,7 @@ We need an instance to emulate client. It is possible to have many producers. -#HSLIDE +--- ### Practice 2 #### We have Math-maker service implementation @@ -434,7 +517,7 @@ Math-maker service implementation - GameControllerIntegrationTest::list() -#HSLIDE +--- ### Summary 1. **Threads** are not difficult until concurrency comes 1. **Annotations** help to build meta-information about application and can be used in both compile-time and runtime @@ -445,7 +528,7 @@ Math-maker service implementation 1. Keep learning **HTTP** -#HSLIDE +--- **Оставьте обратную связь** (вам на почту придет анкета) diff --git a/lecture05/presentation/PITCHME.yaml b/lecture05/presentation/PITCHME.yaml index 88e9885f8b..97d63e137f 100644 --- a/lecture05/presentation/PITCHME.yaml +++ b/lecture05/presentation/PITCHME.yaml @@ -1,3 +1,3 @@ -theme-override : lecture05/presentation/assets/css/PITCHME.css -logo : lecture05/presentation/assets/img/atom.png +theme-override : lecture02/presentation/assets/css/PITCHME.css +logo : lecture01/presentation/assets/img/sphere.png slide-number: true diff --git a/lecture05/src/main/java/ru/atom/boot/hw/HelloController.java b/lecture05/src/main/java/ru/atom/boot/hw/HelloController.java deleted file mode 100644 index 7d77c102e8..0000000000 --- a/lecture05/src/main/java/ru/atom/boot/hw/HelloController.java +++ /dev/null @@ -1,21 +0,0 @@ -package ru.atom.boot.hw; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -@Controller -@RequestMapping("hello") -public class HelloController { - - /** - * curl test - * - * curl -i localhost:8080/hello/world - */ - @RequestMapping("world") - @ResponseBody - public String hi() { - return "Hello, Spring-boot World!"; - } -} diff --git a/lecture05/src/main/java/ru/atom/boot/hw/HelloSpringBoot.java b/lecture05/src/main/java/ru/atom/boot/hw/HelloSpringBoot.java deleted file mode 100644 index ec907a58e0..0000000000 --- a/lecture05/src/main/java/ru/atom/boot/hw/HelloSpringBoot.java +++ /dev/null @@ -1,13 +0,0 @@ -package ru.atom.boot.hw; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class HelloSpringBoot { - - public static void main(String[] args) { - SpringApplication.run(HelloSpringBoot.class, args); - } - -} diff --git a/lecture05/src/main/java/ru/atom/boot/mm/MatchMakerApp.java b/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java similarity index 61% rename from lecture05/src/main/java/ru/atom/boot/mm/MatchMakerApp.java rename to lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java index 8fc383f323..57cc119384 100644 --- a/lecture05/src/main/java/ru/atom/boot/mm/MatchMakerApp.java +++ b/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java @@ -1,17 +1,12 @@ -package ru.atom.boot.mm; +package ru.atom.mm; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import ru.atom.thread.mm.MatchMaker; @SpringBootApplication public class MatchMakerApp { public static void main(String[] args) throws Exception { SpringApplication.run(MatchMakerApp.class, args); - - Thread matchMaker = new Thread(new MatchMaker()); - matchMaker.setName("match-maker"); - matchMaker.start(); } } diff --git a/lecture05/src/main/java/ru/atom/boot/mm/ConnectionController.java b/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java similarity index 72% rename from lecture05/src/main/java/ru/atom/boot/mm/ConnectionController.java rename to lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java index aaccdae8ad..17cf04d52a 100644 --- a/lecture05/src/main/java/ru/atom/boot/mm/ConnectionController.java +++ b/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java @@ -1,8 +1,9 @@ -package ru.atom.boot.mm; +package ru.atom.mm.controller; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; @@ -10,16 +11,19 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; -import ru.atom.thread.mm.Connection; -import ru.atom.thread.mm.ConnectionQueue; +import ru.atom.mm.model.Connection; +import ru.atom.mm.service.ConnectionQueue; @Controller @RequestMapping("/connection") public class ConnectionController { - private static final Logger log = LogManager.getLogger(ConnectionController.class); + private static final Logger log = LoggerFactory.getLogger(ConnectionController.class); + @Autowired + private ConnectionQueue connectionQueue; + /** * curl test * @@ -35,7 +39,7 @@ public void connect(@RequestParam("id") long id, @RequestParam("name") String name) { log.info("New connection id={} name={}", id, name); - ConnectionQueue.getInstance().offer(new Connection(id, name)); + connectionQueue.getQueue().offer(new Connection(id, name)); } /** diff --git a/lecture05/src/main/java/ru/atom/boot/mm/GameController.java b/lecture05/src/main/java/ru/atom/mm/controller/GameController.java similarity index 64% rename from lecture05/src/main/java/ru/atom/boot/mm/GameController.java rename to lecture05/src/main/java/ru/atom/mm/controller/GameController.java index 8e131e979a..a38b1f1f6f 100644 --- a/lecture05/src/main/java/ru/atom/boot/mm/GameController.java +++ b/lecture05/src/main/java/ru/atom/mm/controller/GameController.java @@ -1,13 +1,14 @@ -package ru.atom.boot.mm; +package ru.atom.mm.controller; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; -import ru.atom.thread.mm.GameRepository; +import ru.atom.mm.service.GameRepository; /** * Created by sergey on 3/15/17. @@ -16,7 +17,11 @@ @Controller @RequestMapping("/game") public class GameController { - private static final Logger log = LogManager.getLogger(GameController.class); + private static final Logger log = LoggerFactory.getLogger(GameController.class); + + + @Autowired + private GameRepository gameRepository; /** * curl test @@ -30,6 +35,6 @@ public class GameController { @ResponseBody public String list() { log.info("Games list request"); - return GameRepository.getAll().toString(); + return gameRepository.getAll().toString(); } } diff --git a/lecture05/src/main/java/ru/atom/thread/mm/Connection.java b/lecture05/src/main/java/ru/atom/mm/model/Connection.java similarity index 95% rename from lecture05/src/main/java/ru/atom/thread/mm/Connection.java rename to lecture05/src/main/java/ru/atom/mm/model/Connection.java index 759b3302f7..6a50d1834d 100644 --- a/lecture05/src/main/java/ru/atom/thread/mm/Connection.java +++ b/lecture05/src/main/java/ru/atom/mm/model/Connection.java @@ -1,4 +1,4 @@ -package ru.atom.thread.mm; +package ru.atom.mm.model; /** * Created by sergey on 3/14/17. diff --git a/lecture05/src/main/java/ru/atom/thread/mm/GameSession.java b/lecture05/src/main/java/ru/atom/mm/model/GameSession.java similarity index 77% rename from lecture05/src/main/java/ru/atom/thread/mm/GameSession.java rename to lecture05/src/main/java/ru/atom/mm/model/GameSession.java index 567c153ada..efa0ea2c86 100644 --- a/lecture05/src/main/java/ru/atom/thread/mm/GameSession.java +++ b/lecture05/src/main/java/ru/atom/mm/model/GameSession.java @@ -1,7 +1,8 @@ -package ru.atom.thread.mm; +package ru.atom.mm.model; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.atom.mm.service.ConnectionProducer; import java.util.Arrays; import java.util.concurrent.atomic.AtomicLong; @@ -10,7 +11,8 @@ * Created by sergey on 3/14/17. */ public class GameSession { - private static final Logger log = LogManager.getLogger(MatchMaker.class); + private static final Logger log = LoggerFactory.getLogger(GameSession.class); + private static AtomicLong idGenerator = new AtomicLong(); public static final int PLAYERS_IN_GAME = 4; diff --git a/lecture05/src/main/java/ru/atom/thread/mm/ConnectionProducer.java b/lecture05/src/main/java/ru/atom/mm/service/ConnectionProducer.java similarity index 56% rename from lecture05/src/main/java/ru/atom/thread/mm/ConnectionProducer.java rename to lecture05/src/main/java/ru/atom/mm/service/ConnectionProducer.java index 7f5eccacce..33c604032e 100644 --- a/lecture05/src/main/java/ru/atom/thread/mm/ConnectionProducer.java +++ b/lecture05/src/main/java/ru/atom/mm/service/ConnectionProducer.java @@ -1,25 +1,33 @@ -package ru.atom.thread.mm; +package ru.atom.mm.service; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.atom.mm.model.Connection; import java.util.concurrent.atomic.AtomicLong; /** * Created by sergey on 3/14/17. */ +@Service public class ConnectionProducer implements Runnable { - private static final Logger log = LogManager.getLogger(ConnectionProducer.class); + private static final Logger log = LoggerFactory.getLogger(ConnectionProducer.class); private static final String[] names = {"John", "Paul", "George", "Someone else"}; private static AtomicLong id = new AtomicLong(); + @Autowired + private ConnectionQueue connectionQueue; + + @Override public void run() { while (!Thread.currentThread().isInterrupted()) { long newId = id.getAndIncrement(); - ConnectionQueue.getInstance().offer(new Connection(newId, names[(int) (newId % names.length)])); + connectionQueue.getQueue().offer(new Connection(newId, names[(int) (newId % names.length)])); log.info("Connection {} added.", newId); try { Thread.sleep(1_000); diff --git a/lecture05/src/main/java/ru/atom/mm/service/ConnectionQueue.java b/lecture05/src/main/java/ru/atom/mm/service/ConnectionQueue.java new file mode 100644 index 0000000000..b38432ba5b --- /dev/null +++ b/lecture05/src/main/java/ru/atom/mm/service/ConnectionQueue.java @@ -0,0 +1,19 @@ +package ru.atom.mm.service; + +import org.springframework.stereotype.Repository; +import ru.atom.mm.model.Connection; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Created by sergey on 3/14/17. + */ +@Repository +public class ConnectionQueue { + private BlockingQueue queue = new LinkedBlockingQueue<>(); + + public BlockingQueue getQueue() { + return queue; + } +} diff --git a/lecture05/src/main/java/ru/atom/mm/service/GameRepository.java b/lecture05/src/main/java/ru/atom/mm/service/GameRepository.java new file mode 100644 index 0000000000..bfdf8b6175 --- /dev/null +++ b/lecture05/src/main/java/ru/atom/mm/service/GameRepository.java @@ -0,0 +1,23 @@ +package ru.atom.mm.service; + +import org.springframework.stereotype.Repository; +import ru.atom.mm.model.GameSession; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by sergey on 3/15/17. + */ +@Repository +public class GameRepository { + private ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public void put(GameSession session) { + map.put(session.getId(), session); + } + + public Collection getAll() { + return map.values(); + } +} diff --git a/lecture05/src/main/java/ru/atom/mm/service/MatchMaker.java b/lecture05/src/main/java/ru/atom/mm/service/MatchMaker.java new file mode 100644 index 0000000000..03d2980ea8 --- /dev/null +++ b/lecture05/src/main/java/ru/atom/mm/service/MatchMaker.java @@ -0,0 +1,56 @@ +package ru.atom.mm.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ru.atom.mm.model.Connection; +import ru.atom.mm.model.GameSession; + +import javax.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Created by sergey on 3/14/17. + */ +@Service +public class MatchMaker implements Runnable { + private static final Logger log = LoggerFactory.getLogger(MatchMaker.class); + + + @Autowired + private ConnectionQueue connectionQueue; + + @Autowired + private GameRepository gameRepository; + + + @PostConstruct + public void startThread() { + new Thread(this, "match-maker").start(); + } + + @Override + public void run() { + log.info("Started"); + List candidates = new ArrayList<>(GameSession.PLAYERS_IN_GAME); + while (!Thread.currentThread().isInterrupted()) { + try { + candidates.add( + connectionQueue.getQueue().poll(10_000, TimeUnit.SECONDS) + ); + } catch (InterruptedException e) { + log.warn("Timeout reached"); + } + + if (candidates.size() == GameSession.PLAYERS_IN_GAME) { + GameSession session = new GameSession(candidates.toArray(new Connection[0])); + log.info(session.toString()); + gameRepository.put(session); + candidates.clear(); + } + } + } +} diff --git a/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierExtendsThread.java b/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierExtendsThread.java index aea5917227..f345718371 100644 --- a/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierExtendsThread.java +++ b/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierExtendsThread.java @@ -1,13 +1,14 @@ package ru.atom.thread.instantiation; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.LoggerFactory; +import ru.atom.mm.service.ConnectionProducer; /** * Created by sergey on 3/14/17. */ public class NotifierExtendsThread extends Thread { - private static final Logger log = LogManager.getLogger(NotifierExtendsThread.class); + private static final org.slf4j.Logger log = LoggerFactory.getLogger(NotifierExtendsThread.class); + @Override public void run() { diff --git a/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierImplementsRunnable.java b/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierImplementsRunnable.java index 530b040258..728cf2886c 100644 --- a/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierImplementsRunnable.java +++ b/lecture05/src/main/java/ru/atom/thread/instantiation/NotifierImplementsRunnable.java @@ -1,13 +1,13 @@ package ru.atom.thread.instantiation; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.LoggerFactory; /** * Created by sergey on 3/14/17. */ public class NotifierImplementsRunnable implements Runnable { - private static final Logger log = LogManager.getLogger(NotifierImplementsRunnable.class); + private static final org.slf4j.Logger log = LoggerFactory.getLogger(NotifierImplementsRunnable.class); + @Override public void run() { diff --git a/lecture05/src/main/java/ru/atom/thread/join/Bomb.java b/lecture05/src/main/java/ru/atom/thread/join/Bomb.java index c78fba368c..76142f01e9 100644 --- a/lecture05/src/main/java/ru/atom/thread/join/Bomb.java +++ b/lecture05/src/main/java/ru/atom/thread/join/Bomb.java @@ -1,13 +1,14 @@ package ru.atom.thread.join; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import org.slf4j.LoggerFactory; +import ru.atom.thread.instantiation.NotifierExtendsThread; /** * Created by sergey on 3/14/17. */ public class Bomb implements Runnable { - private static final Logger log = LogManager.getLogger(Bomb.class); + private static final org.slf4j.Logger log = LoggerFactory.getLogger(Bomb.class); + private int countdownFrom; @@ -21,7 +22,7 @@ public void run() { while (!Thread.currentThread().isInterrupted() && countdownFrom > 0) { - log.info(countdownFrom); + log.info(String.valueOf(countdownFrom)); countdownFrom--; try { diff --git a/lecture05/src/main/java/ru/atom/thread/mm/ConnectionQueue.java b/lecture05/src/main/java/ru/atom/thread/mm/ConnectionQueue.java deleted file mode 100644 index 1f78b1e4ee..0000000000 --- a/lecture05/src/main/java/ru/atom/thread/mm/ConnectionQueue.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.atom.thread.mm; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -/** - * Created by sergey on 3/14/17. - */ -public class ConnectionQueue { - private static BlockingQueue instance = new LinkedBlockingQueue<>(); - - public static BlockingQueue getInstance() { - return instance; - } -} diff --git a/lecture05/src/main/java/ru/atom/thread/mm/GameRepository.java b/lecture05/src/main/java/ru/atom/thread/mm/GameRepository.java deleted file mode 100644 index 0266bede2b..0000000000 --- a/lecture05/src/main/java/ru/atom/thread/mm/GameRepository.java +++ /dev/null @@ -1,19 +0,0 @@ -package ru.atom.thread.mm; - -import java.util.Collection; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Created by sergey on 3/15/17. - */ -public class GameRepository { - private static ConcurrentHashMap map = new ConcurrentHashMap<>(); - - public static void put(GameSession session) { - map.put(session.getId(), session); - } - - public static Collection getAll() { - return map.values(); - } -} diff --git a/lecture05/src/main/java/ru/atom/thread/mm/MatchMaker.java b/lecture05/src/main/java/ru/atom/thread/mm/MatchMaker.java deleted file mode 100644 index 60bcf27807..0000000000 --- a/lecture05/src/main/java/ru/atom/thread/mm/MatchMaker.java +++ /dev/null @@ -1,38 +0,0 @@ -package ru.atom.thread.mm; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Created by sergey on 3/14/17. - */ -public class MatchMaker implements Runnable { - private static final Logger log = LogManager.getLogger(MatchMaker.class); - - - @Override - public void run() { - log.info("Started"); - List candidates = new ArrayList<>(GameSession.PLAYERS_IN_GAME); - while (!Thread.currentThread().isInterrupted()) { - try { - candidates.add( - ConnectionQueue.getInstance().poll(10_000, TimeUnit.SECONDS) - ); - } catch (InterruptedException e) { - log.warn("Timeout reached"); - } - - if (candidates.size() == GameSession.PLAYERS_IN_GAME) { - GameSession session = new GameSession(candidates.toArray(new Connection[0])); - log.info(session); - GameRepository.put(session); - candidates.clear(); - } - } - } -} diff --git a/lecture05/src/main/resources/application.properties b/lecture05/src/main/resources/application.properties index ad1a7e46c0..591936dd85 100644 --- a/lecture05/src/main/resources/application.properties +++ b/lecture05/src/main/resources/application.properties @@ -1 +1,5 @@ -management.security.enabled=false \ No newline at end of file +#server port: +server.port = 8080 +#actuator port: +management.server.port = 7001 +management.endpoints.web.exposure.include=* \ No newline at end of file diff --git a/lecture05/src/test/java/ru/atom/annotation/AnnotationDemoTest.java b/lecture05/src/test/java/ru/atom/annotation/AnnotationDemoTest.java index 2ccd5a4f40..32863622ca 100644 --- a/lecture05/src/test/java/ru/atom/annotation/AnnotationDemoTest.java +++ b/lecture05/src/test/java/ru/atom/annotation/AnnotationDemoTest.java @@ -1,9 +1,10 @@ package ru.atom.annotation; import org.junit.Test; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; +import ru.atom.mm.controller.ConnectionController; +import static junit.framework.TestCase.assertEquals; import static org.assertj.core.api.Assertions.assertThat; @@ -11,19 +12,13 @@ public class AnnotationDemoTest { @Test public void countOverride() throws Exception { - assertThat(AnnotationDemo.getNumberOfAnnotatedMethods( - ru.atom.boot.mm.ConnectionController.class, Override.class)).isEqualTo(0); - } - - @Test - public void countRequestMapping() throws Exception { - assertThat(AnnotationDemo.getNumberOfAnnotatedMethods( - ru.atom.boot.hw.HelloController.class, RequestMapping.class)).isEqualTo(1); + assertEquals(0, AnnotationDemo.getNumberOfAnnotatedMethods( + ConnectionController.class, Override.class)); } @Test public void countResponseStatus() throws Exception { - assertThat(AnnotationDemo.getNumberOfAnnotatedMethods( - ru.atom.boot.mm.ConnectionController.class, ResponseStatus.class)).isEqualTo(1); + assertEquals(1, AnnotationDemo.getNumberOfAnnotatedMethods( + ConnectionController.class, ResponseStatus.class)); } } diff --git a/lecture05/src/test/java/ru/atom/boot/hw/HelloControllerTest.java b/lecture05/src/test/java/ru/atom/boot/hw/HelloControllerTest.java deleted file mode 100644 index a74e350934..0000000000 --- a/lecture05/src/test/java/ru/atom/boot/hw/HelloControllerTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package ru.atom.boot.hw; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringRunner.class) -@WebMvcTest -public class HelloControllerTest { - - - /** - * This is Dependency Injection usage - */ - @Autowired - private MockMvc mockMvc; - - @Test - public void hiTest() throws Exception { - mockMvc.perform(get("/hello/world")) - .andDo(print()) - .andExpect(status().isOk()) - .andExpect(content().string("Hello, Spring-boot World!")); - } - -} \ No newline at end of file diff --git a/lecture05/src/test/java/ru/atom/mm/Config.java b/lecture05/src/test/java/ru/atom/mm/Config.java new file mode 100644 index 0000000000..d35fae2c59 --- /dev/null +++ b/lecture05/src/test/java/ru/atom/mm/Config.java @@ -0,0 +1,25 @@ +package ru.atom.mm; + +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import ru.atom.mm.service.ConnectionProducer; +import ru.atom.mm.service.ConnectionQueue; +import ru.atom.mm.service.GameRepository; + +@TestConfiguration +public class Config { + @Bean + public ConnectionQueue connectionQueue() { + return new ConnectionQueue(); + } + + @Bean + public ConnectionProducer connectionProducer() { + return new ConnectionProducer(); + } + + @Bean + public GameRepository gameRepository() { + return new GameRepository(); + } +} diff --git a/lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerIntegrationTest.java b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java similarity index 91% rename from lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerIntegrationTest.java rename to lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java index cede5d0169..b53356ba2d 100644 --- a/lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerIntegrationTest.java +++ b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java @@ -1,10 +1,11 @@ -package ru.atom.boot.mm; +package ru.atom.mm; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc; @@ -15,11 +16,13 @@ @RunWith(SpringRunner.class) @WebMvcTest +@Import(Config.class) public class ConnectionControllerIntegrationTest { @Autowired MockMvc mockMvc; @Test + @Ignore public void connect() throws Exception { mockMvc.perform(post("/connection/connect") .content("id=1&name=a") diff --git a/lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerTest.java b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerTest.java similarity index 67% rename from lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerTest.java rename to lecture05/src/test/java/ru/atom/mm/ConnectionControllerTest.java index d08cd51c42..d971dd229a 100644 --- a/lecture05/src/test/java/ru/atom/boot/mm/ConnectionControllerTest.java +++ b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerTest.java @@ -1,28 +1,28 @@ -package ru.atom.boot.mm; +package ru.atom.mm; import org.junit.Ignore; import org.junit.Test; +import ru.atom.mm.controller.ConnectionController; -import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@Ignore public class ConnectionControllerTest { @Test - @Ignore public void connect() throws Exception { ConnectionController connectionHandler = new ConnectionController(); - assertThat(connectionHandler.list()).isEmpty(); + assertTrue(connectionHandler.list().isEmpty()); connectionHandler.connect(1, "a"); connectionHandler.connect(2, "b"); connectionHandler.connect(3, "c"); - assertThat(connectionHandler.list()).isNotEmpty(); + assertFalse(connectionHandler.list().isEmpty()); } @Test - @Ignore public void list() throws Exception { assertTrue(false); } diff --git a/lecture05/src/test/java/ru/atom/boot/mm/GameControllerTest.java b/lecture05/src/test/java/ru/atom/mm/GameControllerTest.java similarity index 85% rename from lecture05/src/test/java/ru/atom/boot/mm/GameControllerTest.java rename to lecture05/src/test/java/ru/atom/mm/GameControllerTest.java index f915742de8..f0787a0f4f 100644 --- a/lecture05/src/test/java/ru/atom/boot/mm/GameControllerTest.java +++ b/lecture05/src/test/java/ru/atom/mm/GameControllerTest.java @@ -1,15 +1,14 @@ -package ru.atom.boot.mm; +package ru.atom.mm; import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertTrue; - +@Ignore public class GameControllerTest { @Test - @Ignore public void list() throws Exception { assertTrue(false); } diff --git a/lecture05/src/test/java/ru/atom/boot/mm/GamesControllerIntegrationTest.java b/lecture05/src/test/java/ru/atom/mm/GamesControllerIntegrationTest.java similarity index 83% rename from lecture05/src/test/java/ru/atom/boot/mm/GamesControllerIntegrationTest.java rename to lecture05/src/test/java/ru/atom/mm/GamesControllerIntegrationTest.java index bdfa86485e..782a28f6c8 100644 --- a/lecture05/src/test/java/ru/atom/boot/mm/GamesControllerIntegrationTest.java +++ b/lecture05/src/test/java/ru/atom/mm/GamesControllerIntegrationTest.java @@ -1,4 +1,4 @@ -package ru.atom.boot.mm; +package ru.atom.mm; import org.junit.Ignore; import org.junit.Test; @@ -6,10 +6,10 @@ /** * Some annotations here */ +@Ignore public class GamesControllerIntegrationTest { @Test - @Ignore public void list() throws Exception { } diff --git a/lecture05/src/test/java/ru/atom/thread/mm/MatchMakerTest.java b/lecture05/src/test/java/ru/atom/mm/MatchMakerTest.java similarity index 72% rename from lecture05/src/test/java/ru/atom/thread/mm/MatchMakerTest.java rename to lecture05/src/test/java/ru/atom/mm/MatchMakerTest.java index 86de6eeaf8..9765700d3d 100644 --- a/lecture05/src/test/java/ru/atom/thread/mm/MatchMakerTest.java +++ b/lecture05/src/test/java/ru/atom/mm/MatchMakerTest.java @@ -1,7 +1,14 @@ -package ru.atom.thread.mm; +package ru.atom.mm; import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import ru.atom.mm.service.ConnectionProducer; +import ru.atom.mm.service.MatchMaker; import java.util.ArrayList; import java.util.List; @@ -10,8 +17,14 @@ * Created by sergey on 3/14/17. */ @Ignore +@RunWith(SpringRunner.class) +@WebMvcTest +@Import(Config.class) public class MatchMakerTest { + @Autowired + ConnectionProducer connectionProducer; + @Test public void singleProducer() throws Exception { Thread connectionProducer = new Thread(new ConnectionProducer()); diff --git a/lecture05/src/test/java/ru/atom/thread/practice/EventProcessor.java b/lecture05/src/test/java/ru/atom/thread/practice/EventProcessor.java index 2c292e8800..5c09da31fb 100644 --- a/lecture05/src/test/java/ru/atom/thread/practice/EventProcessor.java +++ b/lecture05/src/test/java/ru/atom/thread/practice/EventProcessor.java @@ -8,14 +8,14 @@ */ public class EventProcessor { public static void produceEvents(List eventProducers) { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException();//TODO eventProducers here } public static long countTotalNumberOfGoodEvents() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException();//TODO } public static long countTotalNumberOfBadEvents() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException();//TODO } } diff --git a/lecture06/build.gradle b/lecture06/build.gradle index f522afc734..8cc8bd3b50 100644 --- a/lecture06/build.gradle +++ b/lecture06/build.gradle @@ -1,31 +1,38 @@ -dependencies { - compile rootProject.libraries.spring_boot - compile rootProject.libraries.log4j - compile rootProject.libraries.postgres - compile rootProject.libraries.jetbrainsAnnotations - - testCompile rootProject.libraries.junit - testCompile rootProject.libraries.spring_boot_test +plugins { + id 'org.springframework.boot' version '2.0.0.RELEASE' } -configurations { - compile.exclude group:'ch.qos.logback' +repositories { + mavenCentral() + maven { + url "http://clojars.org/repo/" + } } -springBoot { - mainClass = "ru.atom.lecture06.server.ChatApplication" -} +apply plugin: 'java' +apply plugin: 'checkstyle' +dependencies { + // https://mvnrepository.com/artifact/org.slf4j/slf4j-api + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25' + // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl + //compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.10.0' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web + compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator + compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.RELEASE' + // https://mvnrepository.com/artifact/postgresql/postgresql + compile group: 'postgresql', name: 'postgresql', version: '9.3-1102.jdbc41' -sourceSets { - main { - java { - srcDirs = ['src/main/java'] - } - } - test { - java { - srcDirs = ['src/test/java'] - } - } + + // https://mvnrepository.com/artifact/junit/junit + testCompile group: 'junit', name: 'junit', version: '4.4' + // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test + testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.0.RELEASE' } + +checkstyle { + ignoreFailures = false + toolVersion = '7.5' + configFile = new File('../config/checkstyle/checkstyle.xml') +} \ No newline at end of file diff --git a/lecture06/gradle/wrapper/gradle-wrapper.jar b/lecture06/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..c44b679acd Binary files /dev/null and b/lecture06/gradle/wrapper/gradle-wrapper.jar differ diff --git a/lecture06/gradle/wrapper/gradle-wrapper.properties b/lecture06/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..f51202dd25 --- /dev/null +++ b/lecture06/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/lecture06/gradlew b/lecture06/gradlew new file mode 100755 index 0000000000..cccdd3d517 --- /dev/null +++ b/lecture06/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/lecture06/gradlew.bat b/lecture06/gradlew.bat new file mode 100644 index 0000000000..e95643d6a2 --- /dev/null +++ b/lecture06/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lecture06/lecture06.iml b/lecture06/lecture06.iml new file mode 100644 index 0000000000..87da47998c --- /dev/null +++ b/lecture06/lecture06.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lecture06/presentation/PITCHME.md b/lecture06/presentation/PITCHME.md index d3bc01d6ac..7f619f2990 100644 --- a/lecture06/presentation/PITCHME.md +++ b/lecture06/presentation/PITCHME.md @@ -1,19 +1,21 @@ -#HSLIDE +--- # Java lecture 6 ## Java + DB -#HSLIDE +--- ## Отметьтесь на портале -https://atom.mail.ru/ +https://sphere.mail.ru/ -#HSLIDE +--- ### get ready #1 +[https://github.com/rybalkinsd/atom](https://github.com/rybalkinsd/atom) ```bash > git fetch upstream > git checkout -b lecture06 upstream/lecture06 +> cd lecture06 Refresh gradle project ``` @@ -21,13 +23,13 @@ Refresh gradle project Refresh gradle project -#HSLIDE +--- ### get ready #2 PostgreSQL client linux ```bash -apt-get install postgresql-9.4 +apt-get install postgresql-9.5 ``` windows [[Download page]](https://www.postgresql.org/download/windows/) @@ -38,10 +40,10 @@ mac > brew install postgres ``` -#HSLIDE +--- ### get ready #3 ```bash -> psql -h 34.229.108.81 -U -d atomN +> psql -h 54.224.37.210 -U atomN -d chatdb_atomN > enter your password >> psql (9.6.2, server 9.2.18) >> Type "help" for help. @@ -50,22 +52,35 @@ mac select * from pg_catalog.pg_tables; ``` -`\q to exit :)` +--- +### psql commands +```bash +#exit +\q +#list all schemas +\dn +#list all tables in all schemas +\dt *. +#describe table +\d+ tablename +``` + -#HSLIDE +--- ### Agenda -1. Retrospective 1. DB or not DB 1. Database baseline 1. SQL baseline 1. Java + DB +--- +### Agenda +1. **[DB or not DB]** +1. Database baseline +1. SQL baseline +1. Java + DB -#HSLIDE -process - - -#HSLIDE +--- ### Storage comparison **RAM** vs **File** - Capacity @@ -73,7 +88,7 @@ select * from pg_catalog.pg_tables; - Durability -#HSLIDE +--- ### Storage comparison **File** vs **Database** - Store overhead @@ -81,7 +96,7 @@ select * from pg_catalog.pg_tables; - Guarantees - Speed -#HSLIDE +--- ### Database (RDBMS) Is a @@ -96,14 +111,13 @@ Within Management system -#HSLIDE -### DB types -- SQL -- NoSQL -- In-memory -- embedded +--- +### Many different types of DBs +- SQL/[NoSQL](https://en.wikipedia.org/wiki/NoSQL) +- In-memory/disk storage +- stand-alone/embedded -#HSLIDE +--- ### Transaction Transaction is a unit of work @@ -115,17 +129,17 @@ Transaction is a unit of work - Durability -#HSLIDE +--- ## All examples below are in PostgreSQL [[Official doc]](https://www.postgresql.org/docs/9.2/static/index.html) -#HSLIDE +--- ### Table ```postgresql create table user ( id serial not null, - login varchar(20) unique not null, + login varchar(20) unique not null ); ``` **There is an error in create query** @@ -133,7 +147,7 @@ create table user ( [[Read more about `serial`]](https://www.tutorialspoint.com/postgresql/postgresql_using_autoincrement.htm) -#HSLIDE +--- ### Primary key Indicates that a column or group of columns can be used as a unique identifier for rows in the table @@ -147,7 +161,7 @@ create table chat.user ( ``` -#HSLIDE +--- ### Schema A schema is essentially a namespace. @@ -164,12 +178,12 @@ create table chat.user ( [[Read more]](https://www.postgresql.org/docs/9.3/static/sql-createschema.html) -#HSLIDE +--- ### First schema @See resources/sql/schema/schema-1-simple.sql -#HSLIDE +--- ### CRUD 1. **insert** for create 1. **select** for read @@ -177,7 +191,7 @@ create table chat.user ( 1. **delete** for delete -#HSLIDE +--- ### select ```postgresql select * @@ -187,7 +201,7 @@ where time > '2017-03-25'; [[Read more]](https://www.postgresql.org/docs/9.2/static/sql-select.html) -#HSLIDE +--- ### insert ```postgresql insert into chat.user (login) @@ -196,7 +210,7 @@ values ('admin'); [[Read more]](https://www.postgresql.org/docs/9.2/static/sql-insert.html) -#HSLIDE +--- ### delete ```postgresql delete from chat.user @@ -206,14 +220,14 @@ where login = 'admin'; [[Read more]](https://www.postgresql.org/docs/9.2/static/sql-delete.html) -#HSLIDE +--- ### Constraints Imagine a user with lots of messages in history. What happens when we delete this user? -#HSLIDE +--- ### Constraints ```postgresql drop table if exists chat.message; @@ -232,12 +246,12 @@ What if chat.user has a complex pk? [[Read more]](https://www.postgresql.org/docs/9.2/static/ddl-constraints.html) -#HSLIDE +--- ### Second schema @See resources/sql/schema/schema-2-constraints.sql -#HSLIDE +--- ### What if one of queries is broken? ```postgresql create table "user"(); @@ -249,8 +263,8 @@ values ('admin', now(), 'super message') ``` -#HSLIDE -### Transation +--- +### Transaction ```postgresql begin; {statements} @@ -258,17 +272,17 @@ commit; ``` -#HSLIDE +--- ### Third schema @See resources/sql/schema/schema-3-transaction.sql -#HSLIDE +--- ### Java Database Connectivity process -#HSLIDE +--- ### Connection ```java import java.sql.*; @@ -279,7 +293,7 @@ Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery("select * from chat.user"); ``` -#HSLIDE +--- ### Dao @See ru.atom.lecture06.server.model @See ru.atom.lecture06.server.dao @@ -289,11 +303,11 @@ ResultSet rs = stm.executeQuery("select * from chat.user"); - dbConnection -#HSLIDE +--- ### Types mapping process -#HSLIDE +--- ### Practice 0) Check that DbConnector uses right **login**, **password** and **database** @@ -305,7 +319,7 @@ Implement it using **MessageDao** **Implement UserDao.getByName(String name)** -#HSLIDE +--- ### Summary 1. JDBC is simple 1. JDBC leads to tones of boiler plate code @@ -313,7 +327,7 @@ Implement it using **MessageDao** 1. Use transactions for atomic operations -#HSLIDE +--- **Оставьте обратную связь** (вам на почту придет анкета) diff --git a/lecture06/presentation/PITCHME.yaml b/lecture06/presentation/PITCHME.yaml index ea67549844..aa3a413189 100644 --- a/lecture06/presentation/PITCHME.yaml +++ b/lecture06/presentation/PITCHME.yaml @@ -1,3 +1,3 @@ theme-override : lecture02/presentation/assets/css/PITCHME.css -logo : lecture01/presentation/assets/img/atom.png -slide-number: true +logo : lecture01/presentation/assets/img/sphere.png +slide-number: true \ No newline at end of file diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java b/lecture06/src/main/java/ru/atom/ChatApplication.java similarity index 89% rename from lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java rename to lecture06/src/main/java/ru/atom/ChatApplication.java index a34cb79822..97a0753dc1 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java +++ b/lecture06/src/main/java/ru/atom/ChatApplication.java @@ -1,4 +1,4 @@ -package ru.atom.lecture06.server; +package ru.atom; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java b/lecture06/src/main/java/ru/atom/controller/ChatController.java similarity index 92% rename from lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java rename to lecture06/src/main/java/ru/atom/controller/ChatController.java index c91a7af219..3ce7296ee4 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java +++ b/lecture06/src/main/java/ru/atom/controller/ChatController.java @@ -1,7 +1,7 @@ -package ru.atom.lecture06.server.controller; +package ru.atom.controller; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -10,10 +10,10 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; -import ru.atom.lecture06.server.model.Message; -import ru.atom.lecture06.server.model.User; -import ru.atom.lecture06.server.dao.MessageDao; -import ru.atom.lecture06.server.dao.UserDao; +import ru.atom.dao.MessageDao; +import ru.atom.dao.UserDao; +import ru.atom.model.Message; +import ru.atom.model.User; import java.util.List; import java.util.stream.Collectors; @@ -21,7 +21,7 @@ @Controller @RequestMapping("chat") public class ChatController { - private static final Logger log = LogManager.getLogger(ChatController.class); + private static final Logger log = LoggerFactory.getLogger(ChatController.class); private final UserDao userDao = new UserDao(); private final MessageDao messageDao = new MessageDao(); diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java b/lecture06/src/main/java/ru/atom/dao/Dao.java similarity index 94% rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java rename to lecture06/src/main/java/ru/atom/dao/Dao.java index 84aa019cdf..4ae3c798bd 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java +++ b/lecture06/src/main/java/ru/atom/dao/Dao.java @@ -1,4 +1,4 @@ -package ru.atom.lecture06.server.dao; +package ru.atom.dao; import java.util.List; import java.util.Optional; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java b/lecture06/src/main/java/ru/atom/dao/DbConnector.java similarity index 74% rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java rename to lecture06/src/main/java/ru/atom/dao/DbConnector.java index 3dcfb76ada..90d1c56728 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java +++ b/lecture06/src/main/java/ru/atom/dao/DbConnector.java @@ -1,10 +1,11 @@ -package ru.atom.lecture06.server.dao; +package ru.atom.dao; /** * Created by sergey on 3/25/17. */ -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.DriverManager; @@ -12,13 +13,13 @@ class DbConnector { - private static final Logger log = LogManager.getLogger(DbConnector.class); + private static final Logger log = LoggerFactory.getLogger(DbConnector.class); private static final String URL_TEMPLATE = "jdbc:postgresql://%s:%d/%s"; private static final String URL; - private static final String HOST = "34.229.108.81"; + private static final String HOST = "54.224.37.210"; private static final int PORT = 5432; - private static final String DB_NAME = "atomN"; + private static final String DB_NAME = "chatdb_atomN"; private static final String USER = "atomN"; private static final String PASSWORD = "atomN"; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java b/lecture06/src/main/java/ru/atom/dao/MessageDao.java similarity index 85% rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java rename to lecture06/src/main/java/ru/atom/dao/MessageDao.java index bcf39b5b27..f77766d4ec 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java +++ b/lecture06/src/main/java/ru/atom/dao/MessageDao.java @@ -1,10 +1,9 @@ -package ru.atom.lecture06.server.dao; +package ru.atom.dao; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.intellij.lang.annotations.Language; -import ru.atom.lecture06.server.model.Message; -import ru.atom.lecture06.server.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.atom.model.Message; +import ru.atom.model.User; import java.sql.Connection; import java.sql.ResultSet; @@ -18,9 +17,8 @@ * Created by sergey on 3/25/17. */ public class MessageDao implements Dao { - private static final Logger log = LogManager.getLogger(MessageDao.class); + private static final Logger log = LoggerFactory.getLogger(MessageDao.class); - @Language("sql") private static final String SELECT_ALL_MESSAGES = "select m.time, m.value, u.* " + "from chat.message as m " + @@ -28,7 +26,6 @@ public class MessageDao implements Dao { " on m.user = u.id " + "order by m.time"; - @Language("sql") private static final String INSERT_MESSAGE_TEMPLATE = "insert into chat.message (\"user\", time, value) " + "values (%d, now(), '%s')"; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java b/lecture06/src/main/java/ru/atom/dao/UserDao.java similarity index 87% rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java rename to lecture06/src/main/java/ru/atom/dao/UserDao.java index 70c14133cf..05424d05b9 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java +++ b/lecture06/src/main/java/ru/atom/dao/UserDao.java @@ -1,9 +1,8 @@ -package ru.atom.lecture06.server.dao; +package ru.atom.dao; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.intellij.lang.annotations.Language; -import ru.atom.lecture06.server.model.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.atom.model.User; import java.sql.Connection; import java.sql.ResultSet; @@ -17,20 +16,17 @@ * Created by sergey on 3/25/17. */ public class UserDao implements Dao { - private static final Logger log = LogManager.getLogger(UserDao.class); + private static final Logger log = LoggerFactory.getLogger(UserDao.class); - @Language("sql") private static final String SELECT_ALL_USERS = "select * " + "from chat.user"; - @Language("sql") private static final String SELECT_ALL_USERS_WHERE = "select * " + "from chat.user " + "where "; - @Language("sql") private static final String INSERT_USER_TEMPLATE = "insert into chat.user (login) " + "values ('%s');"; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java b/lecture06/src/main/java/ru/atom/model/Message.java similarity index 95% rename from lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java rename to lecture06/src/main/java/ru/atom/model/Message.java index 413b8b4cb7..55dea52cb0 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java +++ b/lecture06/src/main/java/ru/atom/model/Message.java @@ -1,4 +1,4 @@ -package ru.atom.lecture06.server.model; +package ru.atom.model; import java.util.Date; diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/model/User.java b/lecture06/src/main/java/ru/atom/model/User.java similarity index 93% rename from lecture06/src/main/java/ru/atom/lecture06/server/model/User.java rename to lecture06/src/main/java/ru/atom/model/User.java index e0bbd2393b..19f78e6739 100644 --- a/lecture06/src/main/java/ru/atom/lecture06/server/model/User.java +++ b/lecture06/src/main/java/ru/atom/model/User.java @@ -1,4 +1,4 @@ -package ru.atom.lecture06.server.model; +package ru.atom.model; /** * Created by sergey on 3/25/17. diff --git a/lecture06/src/main/resources/static/index.html b/lecture06/src/main/resources/static/index.html index 378a9849ae..b5bd89a21b 100644 --- a/lecture06/src/main/resources/static/index.html +++ b/lecture06/src/main/resources/static/index.html @@ -1,49 +1,7 @@ - - + + + - -