├── .actionScriptProperties
├── .externalToolBuilders
└── org.eclipse.wst.validation.validationbuilder.launch
├── .flexProperties
├── .project
├── .settings
├── com.adobe.flexbuilder.project.prefs
└── org.eclipse.core.resources.prefs
├── LICENSING
├── README.markdown
├── docs
└── docs.wiki
├── html-template
├── AC_OETags.js
├── history
│ ├── history.css
│ ├── history.js
│ └── historyFrame.html
├── index.template.html
└── playerProductInstall.swf
├── libs
└── empty
└── src
├── ABPlayer.mxml
├── assets
├── bar.png
├── bt_play.png
├── btn_cfgS_down.png
├── btn_cfgS_up.png
├── btn_cfg_down.png
├── btn_cfg_up.png
├── btn_dmk_down.png
├── btn_dmk_off_down.png
├── btn_dmk_off_up.png
├── btn_dmk_up.png
├── btn_fs_down.png
├── btn_fs_up.png
├── btn_pause_down.png
├── btn_pause_up.png
├── btn_play_down.png
├── btn_play_up.png
├── btn_sound_down.png
├── btn_sound_mute_down.png
├── btn_sound_mute_up.png
├── btn_sound_up.png
├── btn_ss_down.png
├── btn_ss_up.png
├── btn_stop_down.png
├── btn_stop_up.png
├── trackerThumb.png
└── trackerThumbDown.png
├── com
└── adobe
│ └── serialization
│ └── json
│ ├── JSON.as
│ ├── JSONDecoder.as
│ ├── JSONEncoder.as
│ ├── JSONParseError.as
│ ├── JSONToken.as
│ ├── JSONTokenType.as
│ └── JSONTokenizer.as
├── css
└── style.css
├── org
└── kanoha
│ ├── collections
│ ├── LinkedList.as
│ ├── Node.as
│ └── SortedLinkedList.as
│ ├── comment
│ ├── BottomCommentSpaceAllocator.as
│ ├── Comment.as
│ ├── CommentConfig.as
│ ├── CommentFilter.as
│ ├── CommentManager.as
│ ├── CommentSpaceAllocator.as
│ ├── ScrollCommentSpaceAllocator.as
│ └── effects
│ │ └── TimelineEffect.as
│ ├── events
│ ├── LoaderEvent.as
│ ├── NMEvent.as
│ └── NSEvent.as
│ ├── net
│ ├── CommentLoader.as
│ ├── CommentSender.as
│ ├── VideoLoader.as
│ └── XMLLoader.as
│ ├── util
│ ├── CommentListParser.as
│ └── Filters.as
│ └── video
│ ├── NS.as
│ ├── NSComponent.as
│ └── VideoInfo.as
└── skins
├── btnCommentOffSkin.mxml
├── btnCommentOnSkin.mxml
├── btnFullScreenSkin.mxml
├── btnMuteSkin.mxml
├── btnPauseSkin.mxml
├── btnPlaySkin.mxml
├── btnSidebarOffSkin.mxml
├── btnSidebarOnSkin.mxml
├── btnSmallScreenSkin.mxml
├── btnStopSkin.mxml
├── btnVolumeSkin.mxml
└── containerBar.mxml
/.actionScriptProperties:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder.launch:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.flexProperties:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ABPlayer
4 |
5 |
6 |
7 |
8 |
9 | com.adobe.flexbuilder.project.flexbuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.ui.externaltools.ExternalToolBuilder
15 | full,incremental,
16 |
17 |
18 | LaunchConfigHandle
19 | <project>/.externalToolBuilders/org.eclipse.wst.validation.validationbuilder.launch
20 |
21 |
22 |
23 |
24 |
25 | com.adobe.flexbuilder.project.flexnature
26 | com.adobe.flexbuilder.project.actionscriptnature
27 |
28 |
29 |
30 | bin-debug
31 | 2
32 | C:/www/ABPlayer
33 |
34 |
35 | bin-release
36 | 2
37 | C:/www/ABPlayer
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/.settings/com.adobe.flexbuilder.project.prefs:
--------------------------------------------------------------------------------
1 | #Wed Sep 21 13:20:17 CST 2011
2 | eclipse.preferences.version=1
3 | upgradeSDK/fb4=
4 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | #Sat Sep 03 15:43:06 CST 2011
2 | eclipse.preferences.version=1
3 | encoding/=utf-8
4 |
--------------------------------------------------------------------------------
/LICENSING:
--------------------------------------------------------------------------------
1 | LICENSING
2 | =========================
3 | As of Version 1.0.11 ABPlayer will be solely licensed under the MIT License
4 | Versions before 1.0.11 are still under the GPLv2.
5 |
6 | =========================
7 | Copyright (c) 2012 Jim Chen ( CQZ, Jabbany )
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy of
10 | this software and associated documentation files (the "Software"), to deal in the
11 | Software without restriction, including without limitation the rights to use, copy,
12 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
13 | and to permit persons to whom the Software is furnished to do so, subject to the
14 | following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all copies
17 | or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
20 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
22 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 | DEALINGS IN THE SOFTWARE.
25 |
26 | Other Partitions
27 | ====================================================================================
28 | The software contains packages from Adobe that are under their corresponding license
29 | these files are located in com.adobe.serialization. The Flex Platform is also under
30 | license of Adobe Systems Incorporated.
31 |
32 | The following license is extracted from the concerning files:
33 |
34 | Copyright (c) 2008, Adobe Systems Incorporated
35 | All rights reserved.
36 |
37 | Redistribution and use in source and binary forms, with or without
38 | modification, are permitted provided that the following conditions are
39 | met:
40 |
41 | * Redistributions of source code must retain the above copyright notice,
42 | this list of conditions and the following disclaimer.
43 |
44 | * Redistributions in binary form must reproduce the above copyright
45 | notice, this list of conditions and the following disclaimer in the
46 | documentation and/or other materials provided with the distribution.
47 |
48 | * Neither the name of Adobe Systems Incorporated nor the names of its
49 | contributors may be used to endorse or promote products derived from
50 | this software without specific prior written permission.
51 |
52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
53 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
54 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
55 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
56 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
57 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
58 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
59 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
60 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
61 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
62 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 |
64 |
65 | ===============================================================================
66 |
67 | Also this project makes use of the tamaki video container element from
68 | Project!Another Displayer, through modification and partitions of the
69 | CommentSpaceAllocation and CommentManager classes contain modified code
70 | from MukioPlayerPlus. Both projects are released under the MIT License
71 | and you can find the corresponding licenses inside corresponding projects:
72 |
73 | http://code.google.com/p/mukioplayer/
74 | http://code.google.com/p/projectanotherdisplayer/
75 |
76 | ===============================================================================
77 | Resources And Images
78 |
79 | Assets and images used in the project are considered to be released into the
80 | public domain. You may freely use them.
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # 说明 #
2 | ABPlayer的1.0.11版本以及后续版本将不支持Flex 3 SDK 转为使用Flex 4 SDK。
3 |
4 | # Introduction #
5 | ABPlayer is a video player developed in the Flex 3 SDK. It allows users to send comments onto the playing timeline while playing online video. Comments are scrolled across the screen when the video reaches the timeline position of the comment allowing interactive and realtime commenting of the video. It also features bottom, top,positioned and reverse scroll options, that allow users to create closed captioning and subtitles for video. Comments support color, font, size and opacity and can have effects as well.
6 |
7 | ## Compiling ##
8 | ABPlayer is based on the Flex 3.2 SDK, you can compile this in Flash Builder 4.5 by setting the SDK to the older SDK. The css needs to be modified to use the MX namespace as the project doesn't incorporate Spark components.
9 |
10 | ## Translations ##
11 | ABPlayer is by default, offered in Chinese (Simplified), you may directly edit strings to translate into any language you wish. Though some English fonts are not completely approprate for positioned comments. If you wish to open
12 | high level comments to users, you should use a monospace font available cross-platform.
13 |
14 | ## 中文 ##
15 | ABPlayer是一个Flex 3 SDK/Flex 4 SDK下开发的弹幕播放器,它有着不同于MukioPlayer和PADPlayer的一些特性,也兼容了两个播放器的很多优点。ABPlayer有比较高的可扩展性,也是少数在Flex SDK 3 下提供的全方位弹幕播放器。
16 | ABPlayer支持滚动弹幕,顶部/底部弹幕,逆向弹幕和高级定位弹幕,并且支持渐变,色彩和字体。弹幕可以设置透明度,并且有一系列高级的过滤器(弹幕对象过滤),同时默认包含一些视频的透镜。它支持一系列JS扩展功能,包括动态载入视频/切换分P等等。
17 |
18 | 此工程为中文工程,有需求的开发者可以自行Checkout。
19 |
20 | ## Licensing/版权声明 ##
21 | See 'LICENSING' file
--------------------------------------------------------------------------------
/docs/docs.wiki:
--------------------------------------------------------------------------------
1 | Documentation Coming Soon
--------------------------------------------------------------------------------
/html-template/AC_OETags.js:
--------------------------------------------------------------------------------
1 | // Flash Player Version Detection - Rev 1.6
2 | // Detect Client Browser type
3 | // Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved.
4 | var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
5 | var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
6 | var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;
7 |
8 | function ControlVersion()
9 | {
10 | var version;
11 | var axo;
12 | var e;
13 |
14 | // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry
15 |
16 | try {
17 | // version will be set for 7.X or greater players
18 | axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
19 | version = axo.GetVariable("$version");
20 | } catch (e) {
21 | }
22 |
23 | if (!version)
24 | {
25 | try {
26 | // version will be set for 6.X players only
27 | axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
28 |
29 | // installed player is some revision of 6.0
30 | // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
31 | // so we have to be careful.
32 |
33 | // default to the first public version
34 | version = "WIN 6,0,21,0";
35 |
36 | // throws if AllowScripAccess does not exist (introduced in 6.0r47)
37 | axo.AllowScriptAccess = "always";
38 |
39 | // safe to call for 6.0r47 or greater
40 | version = axo.GetVariable("$version");
41 |
42 | } catch (e) {
43 | }
44 | }
45 |
46 | if (!version)
47 | {
48 | try {
49 | // version will be set for 4.X or 5.X player
50 | axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
51 | version = axo.GetVariable("$version");
52 | } catch (e) {
53 | }
54 | }
55 |
56 | if (!version)
57 | {
58 | try {
59 | // version will be set for 3.X player
60 | axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
61 | version = "WIN 3,0,18,0";
62 | } catch (e) {
63 | }
64 | }
65 |
66 | if (!version)
67 | {
68 | try {
69 | // version will be set for 2.X player
70 | axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
71 | version = "WIN 2,0,0,11";
72 | } catch (e) {
73 | version = -1;
74 | }
75 | }
76 |
77 | return version;
78 | }
79 |
80 | // JavaScript helper required to detect Flash Player PlugIn version information
81 | function GetSwfVer(){
82 | // NS/Opera version >= 3 check for Flash plugin in plugin array
83 | var flashVer = -1;
84 |
85 | if (navigator.plugins != null && navigator.plugins.length > 0) {
86 | if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
87 | var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
88 | var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
89 | var descArray = flashDescription.split(" ");
90 | var tempArrayMajor = descArray[2].split(".");
91 | var versionMajor = tempArrayMajor[0];
92 | var versionMinor = tempArrayMajor[1];
93 | var versionRevision = descArray[3];
94 | if (versionRevision == "") {
95 | versionRevision = descArray[4];
96 | }
97 | if (versionRevision[0] == "d") {
98 | versionRevision = versionRevision.substring(1);
99 | } else if (versionRevision[0] == "r") {
100 | versionRevision = versionRevision.substring(1);
101 | if (versionRevision.indexOf("d") > 0) {
102 | versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
103 | }
104 | } else if (versionRevision[0] == "b") {
105 | versionRevision = versionRevision.substring(1);
106 | }
107 | var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
108 | }
109 | }
110 | // MSN/WebTV 2.6 supports Flash 4
111 | else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
112 | // WebTV 2.5 supports Flash 3
113 | else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
114 | // older WebTV supports Flash 2
115 | else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
116 | else if ( isIE && isWin && !isOpera ) {
117 | flashVer = ControlVersion();
118 | }
119 | return flashVer;
120 | }
121 |
122 | // When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
123 | function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision)
124 | {
125 | versionStr = GetSwfVer();
126 | if (versionStr == -1 ) {
127 | return false;
128 | } else if (versionStr != 0) {
129 | if(isIE && isWin && !isOpera) {
130 | // Given "WIN 2,0,0,11"
131 | tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"]
132 | tempString = tempArray[1]; // "2,0,0,11"
133 | versionArray = tempString.split(","); // ['2', '0', '0', '11']
134 | } else {
135 | versionArray = versionStr.split(".");
136 | }
137 | var versionMajor = versionArray[0];
138 | var versionMinor = versionArray[1];
139 | var versionRevision = versionArray[2];
140 |
141 | // is the major.revision >= requested major.revision AND the minor version >= requested minor
142 | if (versionMajor > parseFloat(reqMajorVer)) {
143 | return true;
144 | } else if (versionMajor == parseFloat(reqMajorVer)) {
145 | if (versionMinor > parseFloat(reqMinorVer))
146 | return true;
147 | else if (versionMinor == parseFloat(reqMinorVer)) {
148 | if (versionRevision >= parseFloat(reqRevision))
149 | return true;
150 | }
151 | }
152 | return false;
153 | }
154 | }
155 |
156 | function AC_AddExtension(src, ext)
157 | {
158 | var qIndex = src.indexOf('?');
159 | if ( qIndex != -1)
160 | {
161 | // Add the extention (if needed) before the query params
162 | var path = src.substring(0, qIndex);
163 | if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length))
164 | return src;
165 | else
166 | return src.replace(/\?/, ext+'?');
167 | }
168 | else
169 | {
170 | // Add the extension (if needed) to the end of the URL
171 | if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length))
172 | return src; // Already have extension
173 | else
174 | return src + ext;
175 | }
176 | }
177 |
178 | function AC_Generateobj(objAttrs, params, embedAttrs)
179 | {
180 | var str = '';
181 | if (isIE && isWin && !isOpera)
182 | {
183 | str += '';
190 | } else {
191 | str += '';
195 | }
196 |
197 | document.write(str);
198 | }
199 |
200 | function AC_FL_RunContent(){
201 | var ret =
202 | AC_GetArgs
203 | ( arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
204 | , "application/x-shockwave-flash"
205 | );
206 | AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
207 | }
208 |
209 | function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
210 | var ret = new Object();
211 | ret.embedAttrs = new Object();
212 | ret.params = new Object();
213 | ret.objAttrs = new Object();
214 | for (var i=0; i < args.length; i=i+2){
215 | var currArg = args[i].toLowerCase();
216 |
217 | switch (currArg){
218 | case "classid":
219 | break;
220 | case "pluginspage":
221 | ret.embedAttrs[args[i]] = args[i+1];
222 | break;
223 | case "src":
224 | case "movie":
225 | args[i+1] = AC_AddExtension(args[i+1], ext);
226 | ret.embedAttrs["src"] = args[i+1];
227 | ret.params[srcParamName] = args[i+1];
228 | break;
229 | case "onafterupdate":
230 | case "onbeforeupdate":
231 | case "onblur":
232 | case "oncellchange":
233 | case "onclick":
234 | case "ondblClick":
235 | case "ondrag":
236 | case "ondragend":
237 | case "ondragenter":
238 | case "ondragleave":
239 | case "ondragover":
240 | case "ondrop":
241 | case "onfinish":
242 | case "onfocus":
243 | case "onhelp":
244 | case "onmousedown":
245 | case "onmouseup":
246 | case "onmouseover":
247 | case "onmousemove":
248 | case "onmouseout":
249 | case "onkeypress":
250 | case "onkeydown":
251 | case "onkeyup":
252 | case "onload":
253 | case "onlosecapture":
254 | case "onpropertychange":
255 | case "onreadystatechange":
256 | case "onrowsdelete":
257 | case "onrowenter":
258 | case "onrowexit":
259 | case "onrowsinserted":
260 | case "onstart":
261 | case "onscroll":
262 | case "onbeforeeditfocus":
263 | case "onactivate":
264 | case "onbeforedeactivate":
265 | case "ondeactivate":
266 | case "type":
267 | case "codebase":
268 | ret.objAttrs[args[i]] = args[i+1];
269 | break;
270 | case "id":
271 | case "width":
272 | case "height":
273 | case "align":
274 | case "vspace":
275 | case "hspace":
276 | case "class":
277 | case "title":
278 | case "accesskey":
279 | case "name":
280 | case "tabindex":
281 | ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
282 | break;
283 | default:
284 | ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
285 | }
286 | }
287 | ret.objAttrs["classid"] = classid;
288 | if (mimeType) ret.embedAttrs["type"] = mimeType;
289 | return ret;
290 | }
291 |
292 |
293 |
--------------------------------------------------------------------------------
/html-template/history/history.css:
--------------------------------------------------------------------------------
1 | /* This CSS stylesheet defines styles used by required elements in a flex application page that supports browser history */
2 |
3 | #ie_historyFrame { width: 0px; height: 0px; display:none }
4 | #firefox_anchorDiv { width: 0px; height: 0px; display:none }
5 | #safari_formDiv { width: 0px; height: 0px; display:none }
6 | #safari_rememberDiv { width: 0px; height: 0px; display:none }
7 |
--------------------------------------------------------------------------------
/html-template/history/history.js:
--------------------------------------------------------------------------------
1 | BrowserHistoryUtils = {
2 | addEvent: function(elm, evType, fn, useCapture) {
3 | useCapture = useCapture || false;
4 | if (elm.addEventListener) {
5 | elm.addEventListener(evType, fn, useCapture);
6 | return true;
7 | }
8 | else if (elm.attachEvent) {
9 | var r = elm.attachEvent('on' + evType, fn);
10 | return r;
11 | }
12 | else {
13 | elm['on' + evType] = fn;
14 | }
15 | }
16 | }
17 |
18 | BrowserHistory = (function() {
19 | // type of browser
20 | var browser = {
21 | ie: false,
22 | firefox: false,
23 | safari: false,
24 | opera: false,
25 | version: -1
26 | };
27 |
28 | // if setDefaultURL has been called, our first clue
29 | // that the SWF is ready and listening
30 | //var swfReady = false;
31 |
32 | // the URL we'll send to the SWF once it is ready
33 | //var pendingURL = '';
34 |
35 | // Default app state URL to use when no fragment ID present
36 | var defaultHash = '';
37 |
38 | // Last-known app state URL
39 | var currentHref = document.location.href;
40 |
41 | // Initial URL (used only by IE)
42 | var initialHref = document.location.href;
43 |
44 | // Initial URL (used only by IE)
45 | var initialHash = document.location.hash;
46 |
47 | // History frame source URL prefix (used only by IE)
48 | var historyFrameSourcePrefix = 'history/historyFrame.html?';
49 |
50 | // History maintenance (used only by Safari)
51 | var currentHistoryLength = -1;
52 |
53 | var historyHash = [];
54 |
55 | var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash);
56 |
57 | var backStack = [];
58 | var forwardStack = [];
59 |
60 | var currentObjectId = null;
61 |
62 | //UserAgent detection
63 | var useragent = navigator.userAgent.toLowerCase();
64 |
65 | if (useragent.indexOf("opera") != -1) {
66 | browser.opera = true;
67 | } else if (useragent.indexOf("msie") != -1) {
68 | browser.ie = true;
69 | browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4));
70 | } else if (useragent.indexOf("safari") != -1) {
71 | browser.safari = true;
72 | browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7));
73 | } else if (useragent.indexOf("gecko") != -1) {
74 | browser.firefox = true;
75 | }
76 |
77 | if (browser.ie == true && browser.version == 7) {
78 | window["_ie_firstload"] = false;
79 | }
80 |
81 | // Accessor functions for obtaining specific elements of the page.
82 | function getHistoryFrame()
83 | {
84 | return document.getElementById('ie_historyFrame');
85 | }
86 |
87 | function getAnchorElement()
88 | {
89 | return document.getElementById('firefox_anchorDiv');
90 | }
91 |
92 | function getFormElement()
93 | {
94 | return document.getElementById('safari_formDiv');
95 | }
96 |
97 | function getRememberElement()
98 | {
99 | return document.getElementById("safari_remember_field");
100 | }
101 |
102 | // Get the Flash player object for performing ExternalInterface callbacks.
103 | // Updated for changes to SWFObject2.
104 | function getPlayer(id) {
105 | if (id && document.getElementById(id)) {
106 | var r = document.getElementById(id);
107 | if (typeof r.SetVariable != "undefined") {
108 | return r;
109 | }
110 | else {
111 | var o = r.getElementsByTagName("object");
112 | var e = r.getElementsByTagName("embed");
113 | if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
114 | return o[0];
115 | }
116 | else if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
117 | return e[0];
118 | }
119 | }
120 | }
121 | else {
122 | var o = document.getElementsByTagName("object");
123 | var e = document.getElementsByTagName("embed");
124 | if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
125 | return e[0];
126 | }
127 | else if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
128 | return o[0];
129 | }
130 | else if (o.length > 1 && typeof o[1].SetVariable != "undefined") {
131 | return o[1];
132 | }
133 | }
134 | return undefined;
135 | }
136 |
137 | function getPlayers() {
138 | var players = [];
139 | if (players.length == 0) {
140 | var tmp = document.getElementsByTagName('object');
141 | players = tmp;
142 | }
143 |
144 | if (players.length == 0 || players[0].object == null) {
145 | var tmp = document.getElementsByTagName('embed');
146 | players = tmp;
147 | }
148 | return players;
149 | }
150 |
151 | function getIframeHash() {
152 | var doc = getHistoryFrame().contentWindow.document;
153 | var hash = String(doc.location.search);
154 | if (hash.length == 1 && hash.charAt(0) == "?") {
155 | hash = "";
156 | }
157 | else if (hash.length >= 2 && hash.charAt(0) == "?") {
158 | hash = hash.substring(1);
159 | }
160 | return hash;
161 | }
162 |
163 | /* Get the current location hash excluding the '#' symbol. */
164 | function getHash() {
165 | // It would be nice if we could use document.location.hash here,
166 | // but it's faulty sometimes.
167 | var idx = document.location.href.indexOf('#');
168 | return (idx >= 0) ? document.location.href.substr(idx+1) : '';
169 | }
170 |
171 | /* Get the current location hash excluding the '#' symbol. */
172 | function setHash(hash) {
173 | // It would be nice if we could use document.location.hash here,
174 | // but it's faulty sometimes.
175 | if (hash == '') hash = '#'
176 | document.location.hash = hash;
177 | }
178 |
179 | function createState(baseUrl, newUrl, flexAppUrl) {
180 | return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null };
181 | }
182 |
183 | /* Add a history entry to the browser.
184 | * baseUrl: the portion of the location prior to the '#'
185 | * newUrl: the entire new URL, including '#' and following fragment
186 | * flexAppUrl: the portion of the location following the '#' only
187 | */
188 | function addHistoryEntry(baseUrl, newUrl, flexAppUrl) {
189 |
190 | //delete all the history entries
191 | forwardStack = [];
192 |
193 | if (browser.ie) {
194 | //Check to see if we are being asked to do a navigate for the first
195 | //history entry, and if so ignore, because it's coming from the creation
196 | //of the history iframe
197 | if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) {
198 | currentHref = initialHref;
199 | return;
200 | }
201 | if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) {
202 | newUrl = baseUrl + '#' + defaultHash;
203 | flexAppUrl = defaultHash;
204 | } else {
205 | // for IE, tell the history frame to go somewhere without a '#'
206 | // in order to get this entry into the browser history.
207 | getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl;
208 | }
209 | setHash(flexAppUrl);
210 | } else {
211 |
212 | //ADR
213 | if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) {
214 | initialState = createState(baseUrl, newUrl, flexAppUrl);
215 | } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) {
216 | backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl);
217 | }
218 |
219 | if (browser.safari) {
220 | // for Safari, submit a form whose action points to the desired URL
221 | if (browser.version <= 419.3) {
222 | var file = window.location.pathname.toString();
223 | file = file.substring(file.lastIndexOf("/")+1);
224 | getFormElement().innerHTML = '';
225 | //get the current elements and add them to the form
226 | var qs = window.location.search.substring(1);
227 | var qs_arr = qs.split("&");
228 | for (var i = 0; i < qs_arr.length; i++) {
229 | var tmp = qs_arr[i].split("=");
230 | var elem = document.createElement("input");
231 | elem.type = "hidden";
232 | elem.name = tmp[0];
233 | elem.value = tmp[1];
234 | document.forms.historyForm.appendChild(elem);
235 | }
236 | document.forms.historyForm.submit();
237 | } else {
238 | top.location.hash = flexAppUrl;
239 | }
240 | // We also have to maintain the history by hand for Safari
241 | historyHash[history.length] = flexAppUrl;
242 | _storeStates();
243 | } else {
244 | // Otherwise, write an anchor into the page and tell the browser to go there
245 | addAnchor(flexAppUrl);
246 | setHash(flexAppUrl);
247 | }
248 | }
249 | backStack.push(createState(baseUrl, newUrl, flexAppUrl));
250 | }
251 |
252 | function _storeStates() {
253 | if (browser.safari) {
254 | getRememberElement().value = historyHash.join(",");
255 | }
256 | }
257 |
258 | function handleBackButton() {
259 | //The "current" page is always at the top of the history stack.
260 | var current = backStack.pop();
261 | if (!current) { return; }
262 | var last = backStack[backStack.length - 1];
263 | if (!last && backStack.length == 0){
264 | last = initialState;
265 | }
266 | forwardStack.push(current);
267 | }
268 |
269 | function handleForwardButton() {
270 | //summary: private method. Do not call this directly.
271 |
272 | var last = forwardStack.pop();
273 | if (!last) { return; }
274 | backStack.push(last);
275 | }
276 |
277 | function handleArbitraryUrl() {
278 | //delete all the history entries
279 | forwardStack = [];
280 | }
281 |
282 | /* Called periodically to poll to see if we need to detect navigation that has occurred */
283 | function checkForUrlChange() {
284 |
285 | if (browser.ie) {
286 | if (currentHref != document.location.href && currentHref + '#' != document.location.href) {
287 | //This occurs when the user has navigated to a specific URL
288 | //within the app, and didn't use browser back/forward
289 | //IE seems to have a bug where it stops updating the URL it
290 | //shows the end-user at this point, but programatically it
291 | //appears to be correct. Do a full app reload to get around
292 | //this issue.
293 | if (browser.version < 7) {
294 | currentHref = document.location.href;
295 | document.location.reload();
296 | } else {
297 | if (getHash() != getIframeHash()) {
298 | // this.iframe.src = this.blankURL + hash;
299 | var sourceToSet = historyFrameSourcePrefix + getHash();
300 | getHistoryFrame().src = sourceToSet;
301 | }
302 | }
303 | }
304 | }
305 |
306 | if (browser.safari) {
307 | // For Safari, we have to check to see if history.length changed.
308 | if (currentHistoryLength >= 0 && history.length != currentHistoryLength) {
309 | //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|"));
310 | // If it did change, then we have to look the old state up
311 | // in our hand-maintained array since document.location.hash
312 | // won't have changed, then call back into BrowserManager.
313 | currentHistoryLength = history.length;
314 | var flexAppUrl = historyHash[currentHistoryLength];
315 | if (flexAppUrl == '') {
316 | //flexAppUrl = defaultHash;
317 | }
318 | //ADR: to fix multiple
319 | if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
320 | var pl = getPlayers();
321 | for (var i = 0; i < pl.length; i++) {
322 | pl[i].browserURLChange(flexAppUrl);
323 | }
324 | } else {
325 | getPlayer().browserURLChange(flexAppUrl);
326 | }
327 | _storeStates();
328 | }
329 | }
330 | if (browser.firefox) {
331 | if (currentHref != document.location.href) {
332 | var bsl = backStack.length;
333 |
334 | var urlActions = {
335 | back: false,
336 | forward: false,
337 | set: false
338 | }
339 |
340 | if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) {
341 | urlActions.back = true;
342 | // FIXME: could this ever be a forward button?
343 | // we can't clear it because we still need to check for forwards. Ugg.
344 | // clearInterval(this.locationTimer);
345 | handleBackButton();
346 | }
347 |
348 | // first check to see if we could have gone forward. We always halt on
349 | // a no-hash item.
350 | if (forwardStack.length > 0) {
351 | if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) {
352 | urlActions.forward = true;
353 | handleForwardButton();
354 | }
355 | }
356 |
357 | // ok, that didn't work, try someplace back in the history stack
358 | if ((bsl >= 2) && (backStack[bsl - 2])) {
359 | if (backStack[bsl - 2].flexAppUrl == getHash()) {
360 | urlActions.back = true;
361 | handleBackButton();
362 | }
363 | }
364 |
365 | if (!urlActions.back && !urlActions.forward) {
366 | var foundInStacks = {
367 | back: -1,
368 | forward: -1
369 | }
370 |
371 | for (var i = 0; i < backStack.length; i++) {
372 | if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
373 | arbitraryUrl = true;
374 | foundInStacks.back = i;
375 | }
376 | }
377 | for (var i = 0; i < forwardStack.length; i++) {
378 | if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
379 | arbitraryUrl = true;
380 | foundInStacks.forward = i;
381 | }
382 | }
383 | handleArbitraryUrl();
384 | }
385 |
386 | // Firefox changed; do a callback into BrowserManager to tell it.
387 | currentHref = document.location.href;
388 | var flexAppUrl = getHash();
389 | if (flexAppUrl == '') {
390 | //flexAppUrl = defaultHash;
391 | }
392 | //ADR: to fix multiple
393 | if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
394 | var pl = getPlayers();
395 | for (var i = 0; i < pl.length; i++) {
396 | pl[i].browserURLChange(flexAppUrl);
397 | }
398 | } else {
399 | getPlayer().browserURLChange(flexAppUrl);
400 | }
401 | }
402 | }
403 | //setTimeout(checkForUrlChange, 50);
404 | }
405 |
406 | /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */
407 | function addAnchor(flexAppUrl)
408 | {
409 | if (document.getElementsByName(flexAppUrl).length == 0) {
410 | getAnchorElement().innerHTML += "" + flexAppUrl + "";
411 | }
412 | }
413 |
414 | var _initialize = function () {
415 | if (browser.ie)
416 | {
417 | var scripts = document.getElementsByTagName('script');
418 | for (var i = 0, s; s = scripts[i]; i++) {
419 | if (s.src.indexOf("history.js") > -1) {
420 | var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html");
421 | }
422 | }
423 | historyFrameSourcePrefix = iframe_location + "?";
424 | var src = historyFrameSourcePrefix;
425 |
426 | var iframe = document.createElement("iframe");
427 | iframe.id = 'ie_historyFrame';
428 | iframe.name = 'ie_historyFrame';
429 | //iframe.src = historyFrameSourcePrefix;
430 | try {
431 | document.body.appendChild(iframe);
432 | } catch(e) {
433 | setTimeout(function() {
434 | document.body.appendChild(iframe);
435 | }, 0);
436 | }
437 | }
438 |
439 | if (browser.safari)
440 | {
441 | var rememberDiv = document.createElement("div");
442 | rememberDiv.id = 'safari_rememberDiv';
443 | document.body.appendChild(rememberDiv);
444 | rememberDiv.innerHTML = '';
445 |
446 | var formDiv = document.createElement("div");
447 | formDiv.id = 'safari_formDiv';
448 | document.body.appendChild(formDiv);
449 |
450 | var reloader_content = document.createElement('div');
451 | reloader_content.id = 'safarireloader';
452 | var scripts = document.getElementsByTagName('script');
453 | for (var i = 0, s; s = scripts[i]; i++) {
454 | if (s.src.indexOf("history.js") > -1) {
455 | html = (new String(s.src)).replace(".js", ".html");
456 | }
457 | }
458 | reloader_content.innerHTML = '';
459 | document.body.appendChild(reloader_content);
460 | reloader_content.style.position = 'absolute';
461 | reloader_content.style.left = reloader_content.style.top = '-9999px';
462 | iframe = reloader_content.getElementsByTagName('iframe')[0];
463 |
464 | if (document.getElementById("safari_remember_field").value != "" ) {
465 | historyHash = document.getElementById("safari_remember_field").value.split(",");
466 | }
467 |
468 | }
469 |
470 | if (browser.firefox)
471 | {
472 | var anchorDiv = document.createElement("div");
473 | anchorDiv.id = 'firefox_anchorDiv';
474 | document.body.appendChild(anchorDiv);
475 | }
476 |
477 | //setTimeout(checkForUrlChange, 50);
478 | }
479 |
480 | return {
481 | historyHash: historyHash,
482 | backStack: function() { return backStack; },
483 | forwardStack: function() { return forwardStack },
484 | getPlayer: getPlayer,
485 | initialize: function(src) {
486 | _initialize(src);
487 | },
488 | setURL: function(url) {
489 | document.location.href = url;
490 | },
491 | getURL: function() {
492 | return document.location.href;
493 | },
494 | getTitle: function() {
495 | return document.title;
496 | },
497 | setTitle: function(title) {
498 | try {
499 | backStack[backStack.length - 1].title = title;
500 | } catch(e) { }
501 | //if on safari, set the title to be the empty string.
502 | if (browser.safari) {
503 | if (title == "") {
504 | try {
505 | var tmp = window.location.href.toString();
506 | title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#"));
507 | } catch(e) {
508 | title = "";
509 | }
510 | }
511 | }
512 | document.title = title;
513 | },
514 | setDefaultURL: function(def)
515 | {
516 | defaultHash = def;
517 | def = getHash();
518 | //trailing ? is important else an extra frame gets added to the history
519 | //when navigating back to the first page. Alternatively could check
520 | //in history frame navigation to compare # and ?.
521 | if (browser.ie)
522 | {
523 | window['_ie_firstload'] = true;
524 | var sourceToSet = historyFrameSourcePrefix + def;
525 | var func = function() {
526 | getHistoryFrame().src = sourceToSet;
527 | window.location.replace("#" + def);
528 | setInterval(checkForUrlChange, 50);
529 | }
530 | try {
531 | func();
532 | } catch(e) {
533 | window.setTimeout(function() { func(); }, 0);
534 | }
535 | }
536 |
537 | if (browser.safari)
538 | {
539 | currentHistoryLength = history.length;
540 | if (historyHash.length == 0) {
541 | historyHash[currentHistoryLength] = def;
542 | var newloc = "#" + def;
543 | window.location.replace(newloc);
544 | } else {
545 | //alert(historyHash[historyHash.length-1]);
546 | }
547 | //setHash(def);
548 | setInterval(checkForUrlChange, 50);
549 | }
550 |
551 |
552 | if (browser.firefox || browser.opera)
553 | {
554 | var reg = new RegExp("#" + def + "$");
555 | if (window.location.toString().match(reg)) {
556 | } else {
557 | var newloc ="#" + def;
558 | window.location.replace(newloc);
559 | }
560 | setInterval(checkForUrlChange, 50);
561 | //setHash(def);
562 | }
563 |
564 | },
565 |
566 | /* Set the current browser URL; called from inside BrowserManager to propagate
567 | * the application state out to the container.
568 | */
569 | setBrowserURL: function(flexAppUrl, objectId) {
570 | if (browser.ie && typeof objectId != "undefined") {
571 | currentObjectId = objectId;
572 | }
573 | //fromIframe = fromIframe || false;
574 | //fromFlex = fromFlex || false;
575 | //alert("setBrowserURL: " + flexAppUrl);
576 | //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ;
577 |
578 | var pos = document.location.href.indexOf('#');
579 | var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href;
580 | var newUrl = baseUrl + '#' + flexAppUrl;
581 |
582 | if (document.location.href != newUrl && document.location.href + '#' != newUrl) {
583 | currentHref = newUrl;
584 | addHistoryEntry(baseUrl, newUrl, flexAppUrl);
585 | currentHistoryLength = history.length;
586 | }
587 |
588 | return false;
589 | },
590 |
591 | browserURLChange: function(flexAppUrl) {
592 | var objectId = null;
593 | if (browser.ie && currentObjectId != null) {
594 | objectId = currentObjectId;
595 | }
596 | pendingURL = '';
597 |
598 | if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
599 | var pl = getPlayers();
600 | for (var i = 0; i < pl.length; i++) {
601 | try {
602 | pl[i].browserURLChange(flexAppUrl);
603 | } catch(e) { }
604 | }
605 | } else {
606 | try {
607 | getPlayer(objectId).browserURLChange(flexAppUrl);
608 | } catch(e) { }
609 | }
610 |
611 | currentObjectId = null;
612 | }
613 |
614 | }
615 |
616 | })();
617 |
618 | // Initialization
619 |
620 | // Automated unit testing and other diagnostics
621 |
622 | function setURL(url)
623 | {
624 | document.location.href = url;
625 | }
626 |
627 | function backButton()
628 | {
629 | history.back();
630 | }
631 |
632 | function forwardButton()
633 | {
634 | history.forward();
635 | }
636 |
637 | function goForwardOrBackInHistory(step)
638 | {
639 | history.go(step);
640 | }
641 |
642 | //BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); });
643 | (function(i) {
644 | var u =navigator.userAgent;var e=/*@cc_on!@*/false;
645 | var st = setTimeout;
646 | if(/webkit/i.test(u)){
647 | st(function(){
648 | var dr=document.readyState;
649 | if(dr=="loaded"||dr=="complete"){i()}
650 | else{st(arguments.callee,10);}},10);
651 | } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
652 | document.addEventListener("DOMContentLoaded",i,false);
653 | } else if(e){
654 | (function(){
655 | var t=document.createElement('doc:rdy');
656 | try{t.doScroll('left');
657 | i();t=null;
658 | }catch(e){st(arguments.callee,0);}})();
659 | } else{
660 | window.onload=i;
661 | }
662 | })( function() {BrowserHistory.initialize();} );
663 |
--------------------------------------------------------------------------------
/html-template/history/historyFrame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
27 | Hidden frame for Browser History support.
28 |
29 |
30 |
--------------------------------------------------------------------------------
/html-template/index.template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | ${title}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
44 |
45 |
46 |
47 |
103 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/html-template/playerProductInstall.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/html-template/playerProductInstall.swf
--------------------------------------------------------------------------------
/libs/empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/libs/empty
--------------------------------------------------------------------------------
/src/assets/bar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/bar.png
--------------------------------------------------------------------------------
/src/assets/bt_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/bt_play.png
--------------------------------------------------------------------------------
/src/assets/btn_cfgS_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_cfgS_down.png
--------------------------------------------------------------------------------
/src/assets/btn_cfgS_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_cfgS_up.png
--------------------------------------------------------------------------------
/src/assets/btn_cfg_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_cfg_down.png
--------------------------------------------------------------------------------
/src/assets/btn_cfg_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_cfg_up.png
--------------------------------------------------------------------------------
/src/assets/btn_dmk_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_dmk_down.png
--------------------------------------------------------------------------------
/src/assets/btn_dmk_off_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_dmk_off_down.png
--------------------------------------------------------------------------------
/src/assets/btn_dmk_off_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_dmk_off_up.png
--------------------------------------------------------------------------------
/src/assets/btn_dmk_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_dmk_up.png
--------------------------------------------------------------------------------
/src/assets/btn_fs_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_fs_down.png
--------------------------------------------------------------------------------
/src/assets/btn_fs_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_fs_up.png
--------------------------------------------------------------------------------
/src/assets/btn_pause_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_pause_down.png
--------------------------------------------------------------------------------
/src/assets/btn_pause_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_pause_up.png
--------------------------------------------------------------------------------
/src/assets/btn_play_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_play_down.png
--------------------------------------------------------------------------------
/src/assets/btn_play_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_play_up.png
--------------------------------------------------------------------------------
/src/assets/btn_sound_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_sound_down.png
--------------------------------------------------------------------------------
/src/assets/btn_sound_mute_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_sound_mute_down.png
--------------------------------------------------------------------------------
/src/assets/btn_sound_mute_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_sound_mute_up.png
--------------------------------------------------------------------------------
/src/assets/btn_sound_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_sound_up.png
--------------------------------------------------------------------------------
/src/assets/btn_ss_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_ss_down.png
--------------------------------------------------------------------------------
/src/assets/btn_ss_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_ss_up.png
--------------------------------------------------------------------------------
/src/assets/btn_stop_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_stop_down.png
--------------------------------------------------------------------------------
/src/assets/btn_stop_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/btn_stop_up.png
--------------------------------------------------------------------------------
/src/assets/trackerThumb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/trackerThumb.png
--------------------------------------------------------------------------------
/src/assets/trackerThumbDown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jabbany/ABPlayer/9bd87ae43901b024416e2ccab25169f3f48046dd/src/assets/trackerThumbDown.png
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSON.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | /**
37 | * This class provides encoding and decoding of the JSON format.
38 | *
39 | * Example usage:
40 | *
41 | * // create a JSON string from an internal object
42 | * JSON.encode( myObject );
43 | *
44 | * // read a JSON string into an internal object
45 | * var myObject:Object = JSON.decode( jsonString );
46 | *
47 | */
48 | public final class JSON
49 | {
50 | /**
51 | * Encodes a object into a JSON string.
52 | *
53 | * @param o The object to create a JSON string for
54 | * @return the JSON string representing o
55 | * @langversion ActionScript 3.0
56 | * @playerversion Flash 9.0
57 | * @tiptext
58 | */
59 | public static function encode( o:Object ):String
60 | {
61 | return new JSONEncoder( o ).getString();
62 | }
63 |
64 | /**
65 | * Decodes a JSON string into a native object.
66 | *
67 | * @param s The JSON string representing the object
68 | * @param strict Flag indicating if the decoder should strictly adhere
69 | * to the JSON standard or not. The default of true
70 | * throws errors if the format does not match the JSON syntax exactly.
71 | * Pass false
to allow for non-properly-formatted JSON
72 | * strings to be decoded with more leniancy.
73 | * @return A native object as specified by s
74 | * @throw JSONParseError
75 | * @langversion ActionScript 3.0
76 | * @playerversion Flash 9.0
77 | * @tiptext
78 | */
79 | public static function decode( s:String, strict:Boolean = true ):*
80 | {
81 | return new JSONDecoder( s, strict ).getValue();
82 | }
83 |
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONDecoder.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | public class JSONDecoder
37 | {
38 |
39 | /**
40 | * Flag indicating if the parser should be strict about the format
41 | * of the JSON string it is attempting to decode.
42 | */
43 | private var strict:Boolean;
44 |
45 | /** The value that will get parsed from the JSON string */
46 | private var value:*;
47 |
48 | /** The tokenizer designated to read the JSON string */
49 | private var tokenizer:JSONTokenizer;
50 |
51 | /** The current token from the tokenizer */
52 | private var token:JSONToken;
53 |
54 | /**
55 | * Constructs a new JSONDecoder to parse a JSON string
56 | * into a native object.
57 | *
58 | * @param s The JSON string to be converted
59 | * into a native object
60 | * @param strict Flag indicating if the JSON string needs to
61 | * strictly match the JSON standard or not.
62 | * @langversion ActionScript 3.0
63 | * @playerversion Flash 9.0
64 | * @tiptext
65 | */
66 | public function JSONDecoder( s:String, strict:Boolean )
67 | {
68 | this.strict = strict;
69 | tokenizer = new JSONTokenizer( s, strict );
70 |
71 | nextToken();
72 | value = parseValue();
73 |
74 | // Make sure the input stream is empty
75 | if ( strict && nextToken() != null )
76 | {
77 | tokenizer.parseError( "Unexpected characters left in input stream" );
78 | }
79 | }
80 |
81 | /**
82 | * Gets the internal object that was created by parsing
83 | * the JSON string passed to the constructor.
84 | *
85 | * @return The internal object representation of the JSON
86 | * string that was passed to the constructor
87 | * @langversion ActionScript 3.0
88 | * @playerversion Flash 9.0
89 | * @tiptext
90 | */
91 | public function getValue():*
92 | {
93 | return value;
94 | }
95 |
96 | /**
97 | * Returns the next token from the tokenzier reading
98 | * the JSON string
99 | */
100 | private final function nextToken():JSONToken
101 | {
102 | return token = tokenizer.getNextToken();
103 | }
104 |
105 | /**
106 | * Returns the next token from the tokenizer reading
107 | * the JSON string and verifies that the token is valid.
108 | */
109 | private final function nextValidToken():JSONToken
110 | {
111 | token = tokenizer.getNextToken();
112 | checkValidToken();
113 |
114 | return token;
115 | }
116 |
117 | /**
118 | * Verifies that the token is valid.
119 | */
120 | private final function checkValidToken():void
121 | {
122 | // Catch errors when the input stream ends abruptly
123 | if ( token == null )
124 | {
125 | tokenizer.parseError( "Unexpected end of input" );
126 | }
127 | }
128 |
129 | /**
130 | * Attempt to parse an array.
131 | */
132 | private final function parseArray():Array
133 | {
134 | // create an array internally that we're going to attempt
135 | // to parse from the tokenizer
136 | var a:Array = new Array();
137 |
138 | // grab the next token from the tokenizer to move
139 | // past the opening [
140 | nextValidToken();
141 |
142 | // check to see if we have an empty array
143 | if ( token.type == JSONTokenType.RIGHT_BRACKET )
144 | {
145 | // we're done reading the array, so return it
146 | return a;
147 | }
148 | // in non-strict mode an empty array is also a comma
149 | // followed by a right bracket
150 | else if ( !strict && token.type == JSONTokenType.COMMA )
151 | {
152 | // move past the comma
153 | nextValidToken();
154 |
155 | // check to see if we're reached the end of the array
156 | if ( token.type == JSONTokenType.RIGHT_BRACKET )
157 | {
158 | return a;
159 | }
160 | else
161 | {
162 | tokenizer.parseError( "Leading commas are not supported. Expecting ']' but found " + token.value );
163 | }
164 | }
165 |
166 | // deal with elements of the array, and use an "infinite"
167 | // loop because we could have any amount of elements
168 | while ( true )
169 | {
170 | // read in the value and add it to the array
171 | a.push( parseValue() );
172 |
173 | // after the value there should be a ] or a ,
174 | nextValidToken();
175 |
176 | if ( token.type == JSONTokenType.RIGHT_BRACKET )
177 | {
178 | // we're done reading the array, so return it
179 | return a;
180 | }
181 | else if ( token.type == JSONTokenType.COMMA )
182 | {
183 | // move past the comma and read another value
184 | nextToken();
185 |
186 | // Allow arrays to have a comma after the last element
187 | // if the decoder is not in strict mode
188 | if ( !strict )
189 | {
190 | checkValidToken();
191 |
192 | // Reached ",]" as the end of the array, so return it
193 | if ( token.type == JSONTokenType.RIGHT_BRACKET )
194 | {
195 | return a;
196 | }
197 | }
198 | }
199 | else
200 | {
201 | tokenizer.parseError( "Expecting ] or , but found " + token.value );
202 | }
203 | }
204 |
205 | return null;
206 | }
207 |
208 | /**
209 | * Attempt to parse an object.
210 | */
211 | private final function parseObject():Object
212 | {
213 | // create the object internally that we're going to
214 | // attempt to parse from the tokenizer
215 | var o:Object = new Object();
216 |
217 | // store the string part of an object member so
218 | // that we can assign it a value in the object
219 | var key:String
220 |
221 | // grab the next token from the tokenizer
222 | nextValidToken();
223 |
224 | // check to see if we have an empty object
225 | if ( token.type == JSONTokenType.RIGHT_BRACE )
226 | {
227 | // we're done reading the object, so return it
228 | return o;
229 | }
230 | // in non-strict mode an empty object is also a comma
231 | // followed by a right bracket
232 | else if ( !strict && token.type == JSONTokenType.COMMA )
233 | {
234 | // move past the comma
235 | nextValidToken();
236 |
237 | // check to see if we're reached the end of the object
238 | if ( token.type == JSONTokenType.RIGHT_BRACE )
239 | {
240 | return o;
241 | }
242 | else
243 | {
244 | tokenizer.parseError( "Leading commas are not supported. Expecting '}' but found " + token.value );
245 | }
246 | }
247 |
248 | // deal with members of the object, and use an "infinite"
249 | // loop because we could have any amount of members
250 | while ( true )
251 | {
252 | if ( token.type == JSONTokenType.STRING )
253 | {
254 | // the string value we read is the key for the object
255 | key = String( token.value );
256 |
257 | // move past the string to see what's next
258 | nextValidToken();
259 |
260 | // after the string there should be a :
261 | if ( token.type == JSONTokenType.COLON )
262 | {
263 | // move past the : and read/assign a value for the key
264 | nextToken();
265 | o[ key ] = parseValue();
266 |
267 | // move past the value to see what's next
268 | nextValidToken();
269 |
270 | // after the value there's either a } or a ,
271 | if ( token.type == JSONTokenType.RIGHT_BRACE )
272 | {
273 | // we're done reading the object, so return it
274 | return o;
275 | }
276 | else if ( token.type == JSONTokenType.COMMA )
277 | {
278 | // skip past the comma and read another member
279 | nextToken();
280 |
281 | // Allow objects to have a comma after the last member
282 | // if the decoder is not in strict mode
283 | if ( !strict )
284 | {
285 | checkValidToken();
286 |
287 | // Reached ",}" as the end of the object, so return it
288 | if ( token.type == JSONTokenType.RIGHT_BRACE )
289 | {
290 | return o;
291 | }
292 | }
293 | }
294 | else
295 | {
296 | tokenizer.parseError( "Expecting } or , but found " + token.value );
297 | }
298 | }
299 | else
300 | {
301 | tokenizer.parseError( "Expecting : but found " + token.value );
302 | }
303 | }
304 | else
305 | {
306 | tokenizer.parseError( "Expecting string but found " + token.value );
307 | }
308 | }
309 | return null;
310 | }
311 |
312 | /**
313 | * Attempt to parse a value
314 | */
315 | private final function parseValue():Object
316 | {
317 | checkValidToken();
318 |
319 | switch ( token.type )
320 | {
321 | case JSONTokenType.LEFT_BRACE:
322 | return parseObject();
323 |
324 | case JSONTokenType.LEFT_BRACKET:
325 | return parseArray();
326 |
327 | case JSONTokenType.STRING:
328 | case JSONTokenType.NUMBER:
329 | case JSONTokenType.TRUE:
330 | case JSONTokenType.FALSE:
331 | case JSONTokenType.NULL:
332 | return token.value;
333 |
334 | case JSONTokenType.NAN:
335 | if ( !strict )
336 | {
337 | return token.value;
338 | }
339 | else
340 | {
341 | tokenizer.parseError( "Unexpected " + token.value );
342 | }
343 |
344 | default:
345 | tokenizer.parseError( "Unexpected " + token.value );
346 |
347 | }
348 |
349 | return null;
350 | }
351 | }
352 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONEncoder.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | import flash.utils.describeType;
37 |
38 | public class JSONEncoder
39 | {
40 |
41 | /** The string that is going to represent the object we're encoding */
42 | private var jsonString:String;
43 |
44 | /**
45 | * Creates a new JSONEncoder.
46 | *
47 | * @param o The object to encode as a JSON string
48 | * @langversion ActionScript 3.0
49 | * @playerversion Flash 9.0
50 | * @tiptext
51 | */
52 | public function JSONEncoder( value:* )
53 | {
54 | jsonString = convertToString( value );
55 | }
56 |
57 | /**
58 | * Gets the JSON string from the encoder.
59 | *
60 | * @return The JSON string representation of the object
61 | * that was passed to the constructor
62 | * @langversion ActionScript 3.0
63 | * @playerversion Flash 9.0
64 | * @tiptext
65 | */
66 | public function getString():String
67 | {
68 | return jsonString;
69 | }
70 |
71 | /**
72 | * Converts a value to it's JSON string equivalent.
73 | *
74 | * @param value The value to convert. Could be any
75 | * type (object, number, array, etc)
76 | */
77 | private function convertToString( value:* ):String
78 | {
79 | // determine what value is and convert it based on it's type
80 | if ( value is String )
81 | {
82 | // escape the string so it's formatted correctly
83 | return escapeString( value as String );
84 | }
85 | else if ( value is Number )
86 | {
87 | // only encode numbers that finate
88 | return isFinite( value as Number ) ? value.toString() : "null";
89 | }
90 | else if ( value is Boolean )
91 | {
92 | // convert boolean to string easily
93 | return value ? "true" : "false";
94 | }
95 | else if ( value is Array )
96 | {
97 | // call the helper method to convert an array
98 | return arrayToString( value as Array );
99 | }
100 | else if ( value is Object && value != null )
101 | {
102 | // call the helper method to convert an object
103 | return objectToString( value );
104 | }
105 |
106 | return "null";
107 | }
108 |
109 | /**
110 | * Escapes a string accoding to the JSON specification.
111 | *
112 | * @param str The string to be escaped
113 | * @return The string with escaped special characters
114 | * according to the JSON specification
115 | */
116 | private function escapeString( str:String ):String
117 | {
118 | // create a string to store the string's jsonstring value
119 | var s:String = "";
120 | // current character in the string we're processing
121 | var ch:String;
122 | // store the length in a local variable to reduce lookups
123 | var len:Number = str.length;
124 |
125 | // loop over all of the characters in the string
126 | for ( var i:int = 0; i < len; i++ )
127 | {
128 | // examine the character to determine if we have to escape it
129 | ch = str.charAt( i );
130 | switch ( ch )
131 | {
132 | case '"': // quotation mark
133 | s += "\\\"";
134 | break;
135 |
136 | //case '/': // solidus
137 | // s += "\\/";
138 | // break;
139 |
140 | case '\\': // reverse solidus
141 | s += "\\\\";
142 | break;
143 |
144 | case '\b': // bell
145 | s += "\\b";
146 | break;
147 |
148 | case '\f': // form feed
149 | s += "\\f";
150 | break;
151 |
152 | case '\n': // newline
153 | s += "\\n";
154 | break;
155 |
156 | case '\r': // carriage return
157 | s += "\\r";
158 | break;
159 |
160 | case '\t': // horizontal tab
161 | s += "\\t";
162 | break;
163 |
164 | default: // everything else
165 |
166 | // check for a control character and escape as unicode
167 | if ( ch < ' ' )
168 | {
169 | // get the hex digit(s) of the character (either 1 or 2 digits)
170 | var hexCode:String = ch.charCodeAt( 0 ).toString( 16 );
171 |
172 | // ensure that there are 4 digits by adjusting
173 | // the # of zeros accordingly.
174 | var zeroPad:String = hexCode.length == 2 ? "00" : "000";
175 |
176 | // create the unicode escape sequence with 4 hex digits
177 | s += "\\u" + zeroPad + hexCode;
178 | }
179 | else
180 | {
181 |
182 | // no need to do any special encoding, just pass-through
183 | s += ch;
184 |
185 | }
186 | } // end switch
187 |
188 | } // end for loop
189 |
190 | return "\"" + s + "\"";
191 | }
192 |
193 | /**
194 | * Converts an array to it's JSON string equivalent
195 | *
196 | * @param a The array to convert
197 | * @return The JSON string representation of a
198 | */
199 | private function arrayToString( a:Array ):String
200 | {
201 | // create a string to store the array's jsonstring value
202 | var s:String = "";
203 |
204 | // loop over the elements in the array and add their converted
205 | // values to the string
206 | var length:int = a.length;
207 | for ( var i:int = 0; i < length; i++ )
208 | {
209 | // when the length is 0 we're adding the first element so
210 | // no comma is necessary
211 | if ( s.length > 0 )
212 | {
213 | // we've already added an element, so add the comma separator
214 | s += ","
215 | }
216 |
217 | // convert the value to a string
218 | s += convertToString( a[ i ] );
219 | }
220 |
221 | // KNOWN ISSUE: In ActionScript, Arrays can also be associative
222 | // objects and you can put anything in them, ie:
223 | // myArray["foo"] = "bar";
224 | //
225 | // These properties aren't picked up in the for loop above because
226 | // the properties don't correspond to indexes. However, we're
227 | // sort of out luck because the JSON specification doesn't allow
228 | // these types of array properties.
229 | //
230 | // So, if the array was also used as an associative object, there
231 | // may be some values in the array that don't get properly encoded.
232 | //
233 | // A possible solution is to instead encode the Array as an Object
234 | // but then it won't get decoded correctly (and won't be an
235 | // Array instance)
236 |
237 | // close the array and return it's string value
238 | return "[" + s + "]";
239 | }
240 |
241 | /**
242 | * Converts an object to it's JSON string equivalent
243 | *
244 | * @param o The object to convert
245 | * @return The JSON string representation of o
246 | */
247 | private function objectToString( o:Object ):String
248 | {
249 | // create a string to store the object's jsonstring value
250 | var s:String = "";
251 |
252 | // determine if o is a class instance or a plain object
253 | var classInfo:XML = describeType( o );
254 | if ( classInfo.@name.toString() == "Object" )
255 | {
256 | // the value of o[key] in the loop below - store this
257 | // as a variable so we don't have to keep looking up o[key]
258 | // when testing for valid values to convert
259 | var value:Object;
260 |
261 | // loop over the keys in the object and add their converted
262 | // values to the string
263 | for ( var key:String in o )
264 | {
265 | // assign value to a variable for quick lookup
266 | value = o[ key ];
267 |
268 | // don't add function's to the JSON string
269 | if ( value is Function )
270 | {
271 | // skip this key and try another
272 | continue;
273 | }
274 |
275 | // when the length is 0 we're adding the first item so
276 | // no comma is necessary
277 | if ( s.length > 0 )
278 | {
279 | // we've already added an item, so add the comma separator
280 | s += ","
281 | }
282 |
283 | s += escapeString( key ) + ":" + convertToString( value );
284 | }
285 | }
286 | else // o is a class instance
287 | {
288 | // Loop over all of the variables and accessors in the class and
289 | // serialize them along with their values.
290 | for each ( var v:XML in classInfo..*.(
291 | name() == "variable"
292 | ||
293 | (
294 | name() == "accessor"
295 | // Issue #116 - Make sure accessors are readable
296 | && attribute( "access" ).charAt( 0 ) == "r" )
297 | ) )
298 | {
299 | // Issue #110 - If [Transient] metadata exists, then we should skip
300 | if ( v.metadata && v.metadata.( @name == "Transient" ).length() > 0 )
301 | {
302 | continue;
303 | }
304 |
305 | // When the length is 0 we're adding the first item so
306 | // no comma is necessary
307 | if ( s.length > 0 )
308 | {
309 | // We've already added an item, so add the comma separator
310 | s += ","
311 | }
312 |
313 | s += escapeString( v.@name.toString() ) + ":"
314 | + convertToString( o[ v.@name ] );
315 | }
316 | }
317 |
318 | return "{" + s + "}";
319 | }
320 |
321 | }
322 |
323 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONParseError.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | /**
37 | *
38 | *
39 | */
40 | public class JSONParseError extends Error
41 | {
42 |
43 | /** The location in the string where the error occurred */
44 | private var _location:int;
45 |
46 | /** The string in which the parse error occurred */
47 | private var _text:String;
48 |
49 | /**
50 | * Constructs a new JSONParseError.
51 | *
52 | * @param message The error message that occured during parsing
53 | * @langversion ActionScript 3.0
54 | * @playerversion Flash 9.0
55 | * @tiptext
56 | */
57 | public function JSONParseError( message:String = "", location:int = 0, text:String = "" )
58 | {
59 | super( message );
60 | name = "JSONParseError";
61 | _location = location;
62 | _text = text;
63 | }
64 |
65 | /**
66 | * Provides read-only access to the location variable.
67 | *
68 | * @return The location in the string where the error occurred
69 | * @langversion ActionScript 3.0
70 | * @playerversion Flash 9.0
71 | * @tiptext
72 | */
73 | public function get location():int
74 | {
75 | return _location;
76 | }
77 |
78 | /**
79 | * Provides read-only access to the text variable.
80 | *
81 | * @return The string in which the error occurred
82 | * @langversion ActionScript 3.0
83 | * @playerversion Flash 9.0
84 | * @tiptext
85 | */
86 | public function get text():String
87 | {
88 | return _text;
89 | }
90 | }
91 |
92 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONToken.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | public final class JSONToken
37 | {
38 |
39 | /**
40 | * The type of the token.
41 | *
42 | * @langversion ActionScript 3.0
43 | * @playerversion Flash 9.0
44 | * @tiptext
45 | */
46 | public var type:int;
47 |
48 | /**
49 | * The value of the token
50 | *
51 | * @langversion ActionScript 3.0
52 | * @playerversion Flash 9.0
53 | * @tiptext
54 | */
55 | public var value:Object;
56 |
57 | /**
58 | * Creates a new JSONToken with a specific token type and value.
59 | *
60 | * @param type The JSONTokenType of the token
61 | * @param value The value of the token
62 | * @langversion ActionScript 3.0
63 | * @playerversion Flash 9.0
64 | * @tiptext
65 | */
66 | public function JSONToken( type:int = -1 /* JSONTokenType.UNKNOWN */, value:Object = null )
67 | {
68 | this.type = type;
69 | this.value = value;
70 | }
71 |
72 | /**
73 | * Reusable token instance.
74 | *
75 | * @see #create()
76 | */
77 | internal static const token:JSONToken = new JSONToken();
78 |
79 | /**
80 | * Factory method to create instances. Because we don't need more than one instance
81 | * of a token at a time, we can always use the same instance to improve performance
82 | * and reduce memory consumption during decoding.
83 | */
84 | internal static function create( type:int = -1 /* JSONTokenType.UNKNOWN */, value:Object = null ):JSONToken
85 | {
86 | token.type = type;
87 | token.value = value;
88 |
89 | return token;
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONTokenType.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | /**
37 | * Class containing constant values for the different types
38 | * of tokens in a JSON encoded string.
39 | */
40 | public final class JSONTokenType
41 | {
42 | public static const UNKNOWN:int = -1;
43 |
44 | public static const COMMA:int = 0;
45 |
46 | public static const LEFT_BRACE:int = 1;
47 |
48 | public static const RIGHT_BRACE:int = 2;
49 |
50 | public static const LEFT_BRACKET:int = 3;
51 |
52 | public static const RIGHT_BRACKET:int = 4;
53 |
54 | public static const COLON:int = 6;
55 |
56 | public static const TRUE:int = 7;
57 |
58 | public static const FALSE:int = 8;
59 |
60 | public static const NULL:int = 9;
61 |
62 | public static const STRING:int = 10;
63 |
64 | public static const NUMBER:int = 11;
65 |
66 | public static const NAN:int = 12;
67 |
68 | }
69 | }
--------------------------------------------------------------------------------
/src/com/adobe/serialization/json/JSONTokenizer.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008, Adobe Systems Incorporated
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are
7 | met:
8 |
9 | * Redistributions of source code must retain the above copyright notice,
10 | this list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 |
16 | * Neither the name of Adobe Systems Incorporated nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | package com.adobe.serialization.json
34 | {
35 |
36 | public class JSONTokenizer
37 | {
38 |
39 | /**
40 | * Flag indicating if the tokenizer should only recognize
41 | * standard JSON tokens. Setting to false
allows
42 | * tokens such as NaN and allows numbers to be formatted as
43 | * hex, etc.
44 | */
45 | private var strict:Boolean;
46 |
47 | /** The object that will get parsed from the JSON string */
48 | private var obj:Object;
49 |
50 | /** The JSON string to be parsed */
51 | private var jsonString:String;
52 |
53 | /** The current parsing location in the JSON string */
54 | private var loc:int;
55 |
56 | /** The current character in the JSON string during parsing */
57 | private var ch:String;
58 |
59 | /**
60 | * The regular expression used to make sure the string does not
61 | * contain invalid control characters.
62 | */
63 | private const controlCharsRegExp:RegExp = /[\x00-\x1F]/;
64 |
65 | /**
66 | * Constructs a new JSONDecoder to parse a JSON string
67 | * into a native object.
68 | *
69 | * @param s The JSON string to be converted
70 | * into a native object
71 | */
72 | public function JSONTokenizer( s:String, strict:Boolean )
73 | {
74 | jsonString = s;
75 | this.strict = strict;
76 | loc = 0;
77 |
78 | // prime the pump by getting the first character
79 | nextChar();
80 | }
81 |
82 | /**
83 | * Gets the next token in the input sting and advances
84 | * the character to the next character after the token
85 | */
86 | public function getNextToken():JSONToken
87 | {
88 | var token:JSONToken = null;
89 |
90 | // skip any whitespace / comments since the last
91 | // token was read
92 | skipIgnored();
93 |
94 | // examine the new character and see what we have...
95 | switch ( ch )
96 | {
97 | case '{':
98 | token = JSONToken.create( JSONTokenType.LEFT_BRACE, ch );
99 | nextChar();
100 | break
101 |
102 | case '}':
103 | token = JSONToken.create( JSONTokenType.RIGHT_BRACE, ch );
104 | nextChar();
105 | break
106 |
107 | case '[':
108 | token = JSONToken.create( JSONTokenType.LEFT_BRACKET, ch );
109 | nextChar();
110 | break
111 |
112 | case ']':
113 | token = JSONToken.create( JSONTokenType.RIGHT_BRACKET, ch );
114 | nextChar();
115 | break
116 |
117 | case ',':
118 | token = JSONToken.create( JSONTokenType.COMMA, ch );
119 | nextChar();
120 | break
121 |
122 | case ':':
123 | token = JSONToken.create( JSONTokenType.COLON, ch );
124 | nextChar();
125 | break;
126 |
127 | case 't': // attempt to read true
128 | var possibleTrue:String = "t" + nextChar() + nextChar() + nextChar();
129 |
130 | if ( possibleTrue == "true" )
131 | {
132 | token = JSONToken.create( JSONTokenType.TRUE, true );
133 | nextChar();
134 | }
135 | else
136 | {
137 | parseError( "Expecting 'true' but found " + possibleTrue );
138 | }
139 |
140 | break;
141 |
142 | case 'f': // attempt to read false
143 | var possibleFalse:String = "f" + nextChar() + nextChar() + nextChar() + nextChar();
144 |
145 | if ( possibleFalse == "false" )
146 | {
147 | token = JSONToken.create( JSONTokenType.FALSE, false );
148 | nextChar();
149 | }
150 | else
151 | {
152 | parseError( "Expecting 'false' but found " + possibleFalse );
153 | }
154 |
155 | break;
156 |
157 | case 'n': // attempt to read null
158 | var possibleNull:String = "n" + nextChar() + nextChar() + nextChar();
159 |
160 | if ( possibleNull == "null" )
161 | {
162 | token = JSONToken.create( JSONTokenType.NULL, null );
163 | nextChar();
164 | }
165 | else
166 | {
167 | parseError( "Expecting 'null' but found " + possibleNull );
168 | }
169 |
170 | break;
171 |
172 | case 'N': // attempt to read NaN
173 | var possibleNaN:String = "N" + nextChar() + nextChar();
174 |
175 | if ( possibleNaN == "NaN" )
176 | {
177 | token = JSONToken.create( JSONTokenType.NAN, NaN );
178 | nextChar();
179 | }
180 | else
181 | {
182 | parseError( "Expecting 'NaN' but found " + possibleNaN );
183 | }
184 |
185 | break;
186 |
187 | case '"': // the start of a string
188 | token = readString();
189 | break;
190 |
191 | default:
192 | // see if we can read a number
193 | if ( isDigit( ch ) || ch == '-' )
194 | {
195 | token = readNumber();
196 | }
197 | else if ( ch == '' )
198 | {
199 | // check for reading past the end of the string
200 | token = null;
201 | }
202 | else
203 | {
204 | // not sure what was in the input string - it's not
205 | // anything we expected
206 | parseError( "Unexpected " + ch + " encountered" );
207 | }
208 | }
209 |
210 | return token;
211 | }
212 |
213 | /**
214 | * Attempts to read a string from the input string. Places
215 | * the character location at the first character after the
216 | * string. It is assumed that ch is " before this method is called.
217 | *
218 | * @return the JSONToken with the string value if a string could
219 | * be read. Throws an error otherwise.
220 | */
221 | private final function readString():JSONToken
222 | {
223 | // Rather than examine the string character-by-character, it's
224 | // faster to use indexOf to try to and find the closing quote character
225 | // and then replace escape sequences after the fact.
226 |
227 | // Start at the current input stream position
228 | var quoteIndex:int = loc;
229 | do
230 | {
231 | // Find the next quote in the input stream
232 | quoteIndex = jsonString.indexOf( "\"", quoteIndex );
233 |
234 | if ( quoteIndex >= 0 )
235 | {
236 | // We found the next double quote character in the string, but we need
237 | // to make sure it is not part of an escape sequence.
238 |
239 | // Keep looping backwards while the previous character is a backslash
240 | var backspaceCount:int = 0;
241 | var backspaceIndex:int = quoteIndex - 1;
242 | while ( jsonString.charAt( backspaceIndex ) == "\\" )
243 | {
244 | backspaceCount++;
245 | backspaceIndex--;
246 | }
247 |
248 | // If we have an even number of backslashes, that means this is the ending quote
249 | if ( ( backspaceCount & 1 ) == 0 )
250 | {
251 | break;
252 | }
253 |
254 | // At this point, the quote was determined to be part of an escape sequence
255 | // so we need to move past the quote index to look for the next one
256 | quoteIndex++;
257 | }
258 | else // There are no more quotes in the string and we haven't found the end yet
259 | {
260 | parseError( "Unterminated string literal" );
261 | }
262 | } while ( true );
263 |
264 | // Unescape the string
265 | // the token for the string we'll try to read
266 | var token:JSONToken = JSONToken.create(
267 | JSONTokenType.STRING,
268 | // Attach resulting string to the token to return it
269 | unescapeString( jsonString.substr( loc, quoteIndex - loc ) ) );
270 |
271 | // Move past the closing quote in the input string. This updates the next
272 | // character in the input stream to be the character one after the closing quote
273 | loc = quoteIndex + 1;
274 | nextChar();
275 |
276 | return token;
277 | }
278 |
279 | /**
280 | * Convert all JavaScript escape characters into normal characters
281 | *
282 | * @param input The input string to convert
283 | * @return Original string with escape characters replaced by real characters
284 | */
285 | public function unescapeString( input:String ):String
286 | {
287 | // Issue #104 - If the string contains any unescaped control characters, this
288 | // is an error in strict mode
289 | if ( strict && controlCharsRegExp.test( input ) )
290 | {
291 | parseError( "String contains unescaped control character (0x00-0x1F)" );
292 | }
293 |
294 | var result:String = "";
295 | var backslashIndex:int = 0;
296 | var nextSubstringStartPosition:int = 0;
297 | var len:int = input.length;
298 | do
299 | {
300 | // Find the next backslash in the input
301 | backslashIndex = input.indexOf( '\\', nextSubstringStartPosition );
302 |
303 | if ( backslashIndex >= 0 )
304 | {
305 | result += input.substr( nextSubstringStartPosition, backslashIndex - nextSubstringStartPosition );
306 |
307 | // Move past the backslash and next character (all escape sequences are
308 | // two characters, except for \u, which will advance this further)
309 | nextSubstringStartPosition = backslashIndex + 2;
310 |
311 | // Check the next character so we know what to escape
312 | var escapedChar:String = input.charAt( backslashIndex + 1 );
313 | switch ( escapedChar )
314 | {
315 | // Try to list the most common expected cases first to improve performance
316 |
317 | case '"':
318 | result += escapedChar;
319 | break; // quotation mark
320 | case '\\':
321 | result += escapedChar;
322 | break; // reverse solidus
323 | case 'n':
324 | result += '\n';
325 | break; // newline
326 | case 'r':
327 | result += '\r';
328 | break; // carriage return
329 | case 't':
330 | result += '\t';
331 | break; // horizontal tab
332 |
333 | // Convert a unicode escape sequence to it's character value
334 | case 'u':
335 |
336 | // Save the characters as a string we'll convert to an int
337 | var hexValue:String = "";
338 |
339 | var unicodeEndPosition:int = nextSubstringStartPosition + 4;
340 |
341 | // Make sure there are enough characters in the string leftover
342 | if ( unicodeEndPosition > len )
343 | {
344 | parseError( "Unexpected end of input. Expecting 4 hex digits after \\u." );
345 | }
346 |
347 | // Try to find 4 hex characters
348 | for ( var i:int = nextSubstringStartPosition; i < unicodeEndPosition; i++ )
349 | {
350 | // get the next character and determine
351 | // if it's a valid hex digit or not
352 | var possibleHexChar:String = input.charAt( i );
353 | if ( !isHexDigit( possibleHexChar ) )
354 | {
355 | parseError( "Excepted a hex digit, but found: " + possibleHexChar );
356 | }
357 |
358 | // Valid hex digit, add it to the value
359 | hexValue += possibleHexChar;
360 | }
361 |
362 | // Convert hexValue to an integer, and use that
363 | // integer value to create a character to add
364 | // to our string.
365 | result += String.fromCharCode( parseInt( hexValue, 16 ) );
366 |
367 | // Move past the 4 hex digits that we just read
368 | nextSubstringStartPosition = unicodeEndPosition;
369 | break;
370 |
371 | case 'f':
372 | result += '\f';
373 | break; // form feed
374 | case '/':
375 | result += '/';
376 | break; // solidus
377 | case 'b':
378 | result += '\b';
379 | break; // bell
380 | default:
381 | result += '\\' + escapedChar; // Couldn't unescape the sequence, so just pass it through
382 | }
383 | }
384 | else
385 | {
386 | // No more backslashes to replace, append the rest of the string
387 | result += input.substr( nextSubstringStartPosition );
388 | break;
389 | }
390 |
391 | } while ( nextSubstringStartPosition < len );
392 |
393 | return result;
394 | }
395 |
396 | /**
397 | * Attempts to read a number from the input string. Places
398 | * the character location at the first character after the
399 | * number.
400 | *
401 | * @return The JSONToken with the number value if a number could
402 | * be read. Throws an error otherwise.
403 | */
404 | private final function readNumber():JSONToken
405 | {
406 | // the string to accumulate the number characters
407 | // into that we'll convert to a number at the end
408 | var input:String = "";
409 |
410 | // check for a negative number
411 | if ( ch == '-' )
412 | {
413 | input += '-';
414 | nextChar();
415 | }
416 |
417 | // the number must start with a digit
418 | if ( !isDigit( ch ) )
419 | {
420 | parseError( "Expecting a digit" );
421 | }
422 |
423 | // 0 can only be the first digit if it
424 | // is followed by a decimal point
425 | if ( ch == '0' )
426 | {
427 | input += ch;
428 | nextChar();
429 |
430 | // make sure no other digits come after 0
431 | if ( isDigit( ch ) )
432 | {
433 | parseError( "A digit cannot immediately follow 0" );
434 | }
435 | // unless we have 0x which starts a hex number, but this
436 | // doesn't match JSON spec so check for not strict mode.
437 | else if ( !strict && ch == 'x' )
438 | {
439 | // include the x in the input
440 | input += ch;
441 | nextChar();
442 |
443 | // need at least one hex digit after 0x to
444 | // be valid
445 | if ( isHexDigit( ch ) )
446 | {
447 | input += ch;
448 | nextChar();
449 | }
450 | else
451 | {
452 | parseError( "Number in hex format require at least one hex digit after \"0x\"" );
453 | }
454 |
455 | // consume all of the hex values
456 | while ( isHexDigit( ch ) )
457 | {
458 | input += ch;
459 | nextChar();
460 | }
461 | }
462 | }
463 | else
464 | {
465 | // read numbers while we can
466 | while ( isDigit( ch ) )
467 | {
468 | input += ch;
469 | nextChar();
470 | }
471 | }
472 |
473 | // check for a decimal value
474 | if ( ch == '.' )
475 | {
476 | input += '.';
477 | nextChar();
478 |
479 | // after the decimal there has to be a digit
480 | if ( !isDigit( ch ) )
481 | {
482 | parseError( "Expecting a digit" );
483 | }
484 |
485 | // read more numbers to get the decimal value
486 | while ( isDigit( ch ) )
487 | {
488 | input += ch;
489 | nextChar();
490 | }
491 | }
492 |
493 | // check for scientific notation
494 | if ( ch == 'e' || ch == 'E' )
495 | {
496 | input += "e"
497 | nextChar();
498 | // check for sign
499 | if ( ch == '+' || ch == '-' )
500 | {
501 | input += ch;
502 | nextChar();
503 | }
504 |
505 | // require at least one number for the exponent
506 | // in this case
507 | if ( !isDigit( ch ) )
508 | {
509 | parseError( "Scientific notation number needs exponent value" );
510 | }
511 |
512 | // read in the exponent
513 | while ( isDigit( ch ) )
514 | {
515 | input += ch;
516 | nextChar();
517 | }
518 | }
519 |
520 | // convert the string to a number value
521 | var num:Number = Number( input );
522 |
523 | if ( isFinite( num ) && !isNaN( num ) )
524 | {
525 | // the token for the number that we've read
526 | return JSONToken.create( JSONTokenType.NUMBER, num );
527 | }
528 | else
529 | {
530 | parseError( "Number " + num + " is not valid!" );
531 | }
532 |
533 | return null;
534 | }
535 |
536 | /**
537 | * Reads the next character in the input
538 | * string and advances the character location.
539 | *
540 | * @return The next character in the input string, or
541 | * null if we've read past the end.
542 | */
543 | private final function nextChar():String
544 | {
545 | return ch = jsonString.charAt( loc++ );
546 | }
547 |
548 | /**
549 | * Advances the character location past any
550 | * sort of white space and comments
551 | */
552 | private final function skipIgnored():void
553 | {
554 | var originalLoc:int;
555 |
556 | // keep trying to skip whitespace and comments as long
557 | // as we keep advancing past the original location
558 | do
559 | {
560 | originalLoc = loc;
561 | skipWhite();
562 | skipComments();
563 | } while ( originalLoc != loc );
564 | }
565 |
566 | /**
567 | * Skips comments in the input string, either
568 | * single-line or multi-line. Advances the character
569 | * to the first position after the end of the comment.
570 | */
571 | private function skipComments():void
572 | {
573 | if ( ch == '/' )
574 | {
575 | // Advance past the first / to find out what type of comment
576 | nextChar();
577 | switch ( ch )
578 | {
579 | case '/': // single-line comment, read through end of line
580 |
581 | // Loop over the characters until we find
582 | // a newline or until there's no more characters left
583 | do
584 | {
585 | nextChar();
586 | } while ( ch != '\n' && ch != '' )
587 |
588 | // move past the \n
589 | nextChar();
590 |
591 | break;
592 |
593 | case '*': // multi-line comment, read until closing */
594 |
595 | // move past the opening *
596 | nextChar();
597 |
598 | // try to find a trailing */
599 | while ( true )
600 | {
601 | if ( ch == '*' )
602 | {
603 | // check to see if we have a closing /
604 | nextChar();
605 | if ( ch == '/' )
606 | {
607 | // move past the end of the closing */
608 | nextChar();
609 | break;
610 | }
611 | }
612 | else
613 | {
614 | // move along, looking if the next character is a *
615 | nextChar();
616 | }
617 |
618 | // when we're here we've read past the end of
619 | // the string without finding a closing */, so error
620 | if ( ch == '' )
621 | {
622 | parseError( "Multi-line comment not closed" );
623 | }
624 | }
625 |
626 | break;
627 |
628 | // Can't match a comment after a /, so it's a parsing error
629 | default:
630 | parseError( "Unexpected " + ch + " encountered (expecting '/' or '*' )" );
631 | }
632 | }
633 |
634 | }
635 |
636 |
637 | /**
638 | * Skip any whitespace in the input string and advances
639 | * the character to the first character after any possible
640 | * whitespace.
641 | */
642 | private final function skipWhite():void
643 | {
644 | // As long as there are spaces in the input
645 | // stream, advance the current location pointer
646 | // past them
647 | while ( isWhiteSpace( ch ) )
648 | {
649 | nextChar();
650 | }
651 |
652 | }
653 |
654 | /**
655 | * Determines if a character is whitespace or not.
656 | *
657 | * @return True if the character passed in is a whitespace
658 | * character
659 | */
660 | private final function isWhiteSpace( ch:String ):Boolean
661 | {
662 | // Check for the whitespace defined in the spec
663 | if ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' )
664 | {
665 | return true;
666 | }
667 | // If we're not in strict mode, we also accept non-breaking space
668 | else if ( !strict && ch.charCodeAt( 0 ) == 160 )
669 | {
670 | return true;
671 | }
672 |
673 | return false;
674 | }
675 |
676 | /**
677 | * Determines if a character is a digit [0-9].
678 | *
679 | * @return True if the character passed in is a digit
680 | */
681 | private final function isDigit( ch:String ):Boolean
682 | {
683 | return ( ch >= '0' && ch <= '9' );
684 | }
685 |
686 | /**
687 | * Determines if a character is a hex digit [0-9A-Fa-f].
688 | *
689 | * @return True if the character passed in is a hex digit
690 | */
691 | private final function isHexDigit( ch:String ):Boolean
692 | {
693 | return ( isDigit( ch ) || ( ch >= 'A' && ch <= 'F' ) || ( ch >= 'a' && ch <= 'f' ) );
694 | }
695 |
696 | /**
697 | * Raises a parsing error with a specified message, tacking
698 | * on the error location and the original string.
699 | *
700 | * @param message The message indicating why the error occurred
701 | */
702 | public final function parseError( message:String ):void
703 | {
704 | throw new JSONParseError( message, loc, jsonString );
705 | }
706 | }
707 |
708 | }
--------------------------------------------------------------------------------
/src/css/style.css:
--------------------------------------------------------------------------------
1 | /* CSS file */
2 | @namespace s "library://ns.adobe.com/flex/spark";
3 | @namespace mx "library://ns.adobe.com/flex/mx";
4 | mx|TabNavigator{
5 | paddingTop:0;
6 | border:0;
7 | }
8 | s|Button{
9 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
10 | color: #000;
11 | font-size: 12px;
12 | font-weight: normal;
13 | }
14 | s|CheckBox{
15 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
16 | color: #000;
17 | font-size: 12px;
18 | font-weight: normal;
19 | }
20 | s|TextInput{
21 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
22 | color: #000;
23 | font-size: 12px;
24 | font-weight: normal;
25 | }
26 | s|Label{
27 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
28 | color: #000;
29 | font-size: 12px;
30 | font-weight: normal;
31 | }
32 | s|DataGrid{
33 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
34 | font-size:11px;
35 | }
36 | s|DataGrid s|Label{
37 | font-family: "Microsoft Yahei","Heiti","黑体","宋体",Helvetica,Arial;
38 | color: #000;
39 | font-size: 12px;
40 | font-weight: normal;
41 | }
42 | mx|Canvas.videoWrapper{
43 | backgroundColor:#000;
44 | }
45 | s|Button.playBtn{
46 | skinClass: ClassReference("skins.btnPlaySkin");
47 | }
48 | s|Button.pauseBtn{
49 | skinClass: ClassReference("skins.btnPauseSkin");
50 | }
51 | s|Button.stopBtn{
52 | skinClass: ClassReference("skins.btnStopSkin");
53 | }
54 | s|Button.fsBtn{
55 | skinClass: ClassReference("skins.btnFullScreenSkin");
56 | }
57 | s|Button.ssBtn{
58 | skinClass: ClassReference("skins.btnSmallScreenSkin");
59 | }
60 | s|Button.cfgBtn{
61 | skinClass: ClassReference("skins.btnSidebarOnSkin");
62 | }
63 | s|Button.cfgSBtn{
64 | skinClass: ClassReference("skins.btnSidebarOffSkin");
65 | }
66 | s|Button.volume{
67 | skinClass: ClassReference("skins.btnVolumeSkin");
68 | }
69 | s|Button.muted{
70 | skinClass: ClassReference("skins.btnMuteSkin");
71 | }
72 | s|Button.cmntOn{
73 | skinClass: ClassReference("skins.btnCommentOnSkin");
74 | }
75 | s|Button.cmntOff{
76 | skinClass: ClassReference("skins.btnCommentOffSkin");
77 | }
78 | s|SkinnableComponent.Bar{
79 | skinClass: ClassReference("skins.containerBar");
80 | }
--------------------------------------------------------------------------------
/src/org/kanoha/collections/LinkedList.as:
--------------------------------------------------------------------------------
1 | /*************************
2 | * LinkedList Modified from tamaki.collection.LinkedList
3 | * ***********************/
4 |
5 | package org.kanoha.collections
6 | {
7 | public class LinkedList
8 | {
9 | protected var head:Node;
10 | protected var tail:Node;
11 | protected var pntr:Node;
12 | protected var length:uint = 0;
13 | public function LinkedList()
14 | {
15 | head = new Node();
16 | tail = new Node();
17 | pntr = head;
18 | head.next = tail;
19 | tail.prev = head;
20 | }
21 | public function push(item:*):void{
22 | var newNode:Node = new Node(item);
23 | tail.prev.next = newNode;
24 | newNode.prev = tail.prev;
25 | newNode.next = tail;
26 | tail.prev = newNode;
27 | length++;
28 | }
29 | public function shift():*{
30 | pntr = head;
31 | if(head.next == tail){
32 | return null;//nothing left!
33 | }
34 | var tn:Node = head.next;
35 | head.next = head.next.next;
36 | head.next.prev = head;
37 | length--;
38 | return tn.data;
39 | }
40 | public function pop():*{
41 | pntr = head;
42 | if(tail.prev == head){
43 | return null;//nothing to pop
44 | }
45 | var tn:Node = tail.prev;
46 | tail.prev = tail.prev.prev;
47 | tail.prev.next = tail;
48 | length--;
49 | return tn.data;
50 | }
51 | public function current():*{
52 | if(!pntr){
53 | return null;
54 | }
55 | return pntr.data;
56 | }
57 | public function forward():*{
58 | if(pntr.next == tail){
59 | return null;//already at the end
60 | }
61 | var tn:Node = pntr.next;
62 | pntr = pntr.next;
63 | return tn.data;
64 | }
65 | public function back():*{
66 | if(pntr.prev == head){
67 | return null;//already at the beginning
68 | }
69 | var tn:Node = pntr.prev;
70 | pntr = pntr.prev;
71 | return tn.data;
72 | }
73 | public function hasNext():Boolean{
74 | if(pntr.next == tail){
75 | return false;
76 | }
77 | return true;
78 | }
79 | public function hasPrev():Boolean{
80 | if(pntr.prev == head){
81 | return false;
82 | }
83 | return true;
84 | }
85 | public function reset():void{
86 | this.pntr = this.head;
87 | }
88 | public function peek():*{
89 | if(pntr.next==tail)
90 | return null;
91 | return pntr.next.data;
92 | }
93 | public function peekback():*{
94 | if(pntr.prev==head)
95 | return null
96 | return pntr.prev.data;
97 | }
98 | public function goLast():void{
99 | this.pntr = this.tail;
100 | }
101 | public function visit(f:Function, target:*=null):void{
102 | this.reset();
103 | while(this.hasNext()){
104 | var item:* = this.forward();
105 | f.call(target,item);
106 | }
107 | }
108 | public function filter(f:Function, target:*=null):void{
109 | this.reset();
110 | while(this.hasNext()){
111 | var item:* = this.forward();
112 | if(!f.call(target,item)){
113 | this.removeCurrent();
114 | }
115 | }
116 | }
117 | public function remove(item:*):Boolean{
118 | this.reset();
119 | while(this.hasNext()){
120 | var ti:* = this.forward();
121 | if(ti==item){
122 | this.removeCurrent();
123 | return true;
124 | }
125 | }
126 | return false;
127 | }
128 | public function removeCurrent():void{
129 | if(pntr!= head && pntr != tail){
130 | pntr.prev.next = pntr.next;
131 | pntr.next.prev = pntr.prev;
132 | pntr = pntr.prev;
133 | length--;
134 | }
135 | }
136 | public function insertAfterCurrent(item:*):void{
137 | if(pntr !=tail){
138 | var tn:Node = new Node(item);
139 | tn.prev = pntr;
140 | tn.next = pntr.next;
141 | pntr.next.prev = tn;
142 | pntr.next = tn;
143 | }
144 | }
145 | public function get size():uint{
146 | return this.length;
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/src/org/kanoha/collections/Node.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.collections
2 | {
3 | public class Node
4 | {
5 | public var next:Node;
6 | public var prev:Node;
7 | public var data:*;
8 | public function Node(data:* = null,next:Node = null, prev:Node = null)
9 | {
10 | this.prev = prev;
11 | this.next = next;
12 | this.data = data;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/org/kanoha/collections/SortedLinkedList.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.collections
2 | {
3 | public class SortedLinkedList extends LinkedList
4 | {
5 | private var compF:Function;
6 | public function SortedLinkedList(cf:Function)
7 | {
8 | this.compF = cf;
9 | }
10 | override public function push(item:*):void{
11 | var tn:Node = new Node(item);
12 | var next:Node = this.findPos(item);
13 | if(next == head){
14 | super.push(item);
15 | }else{
16 | tn.next = next;
17 | tn.prev = next.prev;
18 | next.prev.next = tn;
19 | next.prev = tn;
20 | length++;
21 | }
22 | }
23 | public function pushReverse(item:*):void{
24 | var tn:Node = new Node(item);
25 | var pre:Node = this.findPosReverse(item);
26 | if(pre == tail)
27 | {
28 | super.push(item);
29 | }
30 | else
31 | {
32 | tn.prev = pre;
33 | tn.next = pre.next;
34 | pre.next.prev = tn;
35 | pre.next = tn;
36 | length++;
37 | }
38 | }
39 | private function findPos(item:*):Node{
40 | this.reset();
41 | while(this.hasNext()){
42 | var ti:* = this.forward();
43 | if(this.compF.call(null,item,ti) < 0){
44 | break;
45 | }
46 | }
47 | if(pntr!=head && pntr.next == tail){
48 | //LAST ELEMENT
49 | if(this.compF.call(null,item,this.current()) >=0){
50 | return tail;
51 | }
52 | }
53 | return pntr;
54 | }
55 | private function findPosReverse(item:*):Node{
56 | this.goLast();
57 | while(this.hasPrev()){
58 | var ti:* = this.back();
59 | if(this.compF.call(null,item,ti)>=0){
60 | break;
61 | }
62 | }
63 | if(pntr!=tail && pntr.prev==head){
64 | if(this.compF.call(null,item,ti)<0){
65 | return head;
66 | }
67 | }
68 | return pntr;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/BottomCommentSpaceAllocator.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | public class BottomCommentSpaceAllocator extends CommentSpaceAllocator
4 | {
5 | public function BottomCommentSpaceAllocator()
6 | {
7 | }
8 | override protected function transformY(y:int,cmt:Comment):int
9 | {
10 | return this.Height - y - cmt.height;
11 | }
12 | override protected function vCheck(y:int, cmt:Comment, index:int):Boolean
13 | {
14 | var bottom:int = y + cmt.height;
15 | for each(var c:Comment in this.pools[index])
16 | {
17 | var _y:int = transformY(c.y,c);
18 | if(_y > bottom || c.bottom < y)
19 | {
20 | continue;
21 | }
22 | else
23 | {
24 | return false;
25 | }
26 | }
27 | return true;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/Comment.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | /**
4 | * Comment Object
5 | * Author: CQZ
6 | * This is a combo of MukioPlayerPlus and PAD
7 | * Version 2 - This now uses a different approach as we should support
8 | * Image Based comments too.
9 | * This object represents the specialties of both systems
10 | **/
11 | import flash.text.TextFormat;
12 |
13 | import spark.components.RichText;
14 | import spark.effects.Animate;
15 | import spark.primitives.Rect;
16 |
17 | public class Comment extends RichText
18 | {
19 | protected var _data:Object;
20 | protected var borderBox:Rect;
21 | protected var _index:int;//tracking
22 | protected var _bottom:int;//tracking
23 | protected var _effect:Animate;
24 | protected var _duration:Number=0;
25 | protected var _containerWidth:int=0;
26 | protected var config:CommentConfig = new CommentConfig();//default configurations?!
27 | public function Comment(d:Object){
28 | super();
29 | _data = {};
30 | for (var key:String in d){
31 | _data[key] = d[key];
32 | }
33 | //init();
34 | }
35 | public function setY(py:int,idx:int,trans:Function):void{
36 | this.y = trans(py,this);
37 | this._index = idx;
38 | this._bottom = py + this.height;
39 | }
40 | public function get index():int{
41 | return this._index;
42 | }
43 | override public function get bottom():Object{
44 | return this._bottom;
45 | }
46 | override public function get right():Object{
47 | return this.x + this.width;
48 | }
49 | public function set duration(dur:Number):void{
50 | this._duration = dur;
51 | }
52 | public function get duration():Number{
53 | return this._duration;
54 | }
55 | public function get stime():Number{
56 | return this._data['stime'];
57 | }
58 | public function validateEX():void{
59 | this.validateNow();
60 | this.height = this.measuredHeight;
61 | this.width = this.measuredWidth;
62 | }
63 | public function init():void{
64 | this.visible = true;
65 | if(config.bold){
66 | this.setStyle("fontWeight","bold");
67 | }
68 | //this.textField.defaultTextFormat = new TextFormat(config.font,config.relsize * _data.size, _data.color,config.bold);
69 | this.setStyle("fontSize",config.relsize * _data.size);
70 | this.setStyle("fontFamily",config.font);
71 | this.setStyle("color",_data.color);
72 | this.toolTip="";
73 | if(_data.mode<6){
74 | this.alpha = config.alpha;
75 | }
76 | this.text = _data.text;
77 | if(_data.border){
78 | trace("Border");
79 | }
80 | /*
81 | if(_data.borderColor!=null){
82 | this.textField.borderColor = _data.borderColor;
83 | }else{
84 | this.textField.borderColor = 0x66FFFF;//hmmm
85 | }*/
86 | if(this._data.mode>=7){
87 | this.x = this._data.x;
88 | this.y = this._data.y;
89 | this.rotationZ = this._data.rZ;
90 | this.rotationY = this._data.rY;
91 | //this.rotation = _data.rZ;
92 | //this.rotationZ = _data.rZ;
93 | }
94 | this.filters = config.filter;
95 | if(int(_data.color /65536)<10 && int((_data.color%65536)/256)<10 && (_data.color%256)<10 && (_data.mode == 4 || _data.mode==5)){
96 | this.filters = config.whiteFilter;
97 | }
98 | this.validateEX();
99 | }
100 | public function set borderColor(c:uint):void{
101 | //this.textField.borderColor = c;
102 | }
103 | public function set effect(effect:Animate):void{
104 | this._effect = effect;
105 | }
106 | public function get effect():Animate{
107 | return this._effect;
108 | }
109 | public function get dataObject():Object{
110 | return this._data;
111 | }
112 | public function set defaults(def:CommentConfig):void{
113 | this.config = def;
114 | }
115 | }
116 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/CommentConfig.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | public class CommentConfig
4 | {
5 | import flash.filters.GlowFilter;
6 | private var _$settings:Object = {
7 | bold:true,
8 | alpha:1,
9 | filter:[new GlowFilter(0, 0.7, 3,3)],
10 | whiteFilter:[new GlowFilter(0xffffff, 0.7, 3,3)],
11 | relsize:1,
12 | font:"宋体"
13 | };
14 | public function CommentConfig(init:Object = null)
15 | {
16 | if(init!=null)
17 | this._$settings = init;
18 | }
19 | public static function getDefaults():Object{
20 | var obj:Object = {
21 | bold:true,
22 | alpha:1,
23 | filter:[new GlowFilter(0, 0.7, 3,3)],
24 | whiteFilter:[new GlowFilter(0xffffff, 0.7, 3,3)],
25 | relsize:1,
26 | font:"宋体"
27 | };
28 | return obj;
29 | }
30 | public function get bold():Boolean{
31 | return this._$settings.bold;
32 | }
33 | public function get alpha():Number{
34 | return this._$settings.alpha;
35 | }
36 | public function get filter():Array{
37 | return this._$settings.filter;
38 | }
39 | public function get whiteFilter():Array{
40 | return this._$settings.whiteFilter;
41 | }
42 | public function get relsize():Number{
43 | return this._$settings.relsize;
44 | }
45 | public function get font():String{
46 | return this._$settings.font;
47 | }
48 | public function setStyle(styleKey:String,styleValue:*):void{
49 | this._$settings[styleKey] = styleValue;
50 | }
51 | public function setGlow(glowMode:String):void{
52 | if(glowMode=='none'){
53 | this._$settings['filter']=[];
54 | this._$settings['whiteFilter']=[];
55 | }else if(glowMode=='border'){
56 | this._$settings['filter']=[new GlowFilter(0, 0.7, 3,3)];
57 | this._$settings['whiteFilter']=[new GlowFilter(0xffffff, 0.7, 3,3)];
58 | }else if(glowMode=="highlight"){
59 | this._$settings['filter']=[new GlowFilter(0x34251e, 0.7, 6,6)];
60 | this._$settings['whiteFilter']=[new GlowFilter(0x34251e, 0.7, 6,6)];
61 | }
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/CommentFilter.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | public class CommentFilter
4 | {
5 | protected var filters:Array = new Array();
6 | protected var filterModes:Array = [true,true,true,true,true,true,true,true,true,true];
7 | public function CommentFilter()
8 | {
9 | }
10 | public function clear():void{
11 | this.filters = new Array();//deleted all filters
12 | }
13 | public function addFilter(filter:String):Object{
14 | //Parse this
15 | var entities:Array = filter.split(" ",3);
16 | if(entities.length<3)
17 | return {id:-1};//Not enough parameters
18 | var entMode:Array = String(entities[0]).split(".",2);
19 | var id:int=0;
20 | switch(entMode[0]){
21 | case '$':id=1;break;
22 | case 'T':id=5;break;
23 | case 'B':id=4;break;
24 | case 'P':id=7;break;
25 | case 'R':id=6;break;
26 | case '*':id=0;break;
27 | default:return {id:-2};//Undefined entity mode
28 | }
29 | if(filters[id]==null){
30 | filters[id]=new Array();
31 | }
32 | var objFilter:Object = {property:entMode[1],operator:entities[1],p:entities[2]};
33 | if(objFilter.operator != "region" && objFilter.operator != "subset")
34 | if(objFilter.property == "size" ||objFilter.property == "mode"|| objFilter.property == "stime" || objFilter.property == "width" || objFilter.property == "height" || objFilter.property == "color" && objFilter.p.charAt(0)!="#"){
35 | objFilter.p=int(objFilter.p);
36 | }
37 | filters[id].push(objFilter);
38 | return {id:(filters[id].length - 1),mode:id};
39 | }
40 | public function removeFilterAt(id:int,mode:int=0):Boolean{
41 | try{
42 | filters[mode].splice(id,1);
43 | }catch(e:Error){
44 | //do nothing
45 | return false;
46 | }
47 | return true;
48 | }
49 | public function removeFilter(filter:String):Number{
50 | //Parse this
51 | var entities:Array = filter.split(" ",3);
52 | if(entities.length<3)
53 | return -1;//Not enough parameters
54 | var entMode:Array = String(entities[0]).split(".",2);
55 | var id:int=0;
56 | switch(entMode[0]){
57 | case '$':id=1;break;
58 | case 'T':id=5;break;
59 | case 'B':id=4;break;
60 | case 'P':id=7;break;
61 | case 'R':id=6;break;
62 | case '*':id=0;break;
63 | default:return -2;//Undefined entity mode
64 | }
65 | if(filters[id]==null){
66 | return 0;
67 | }
68 | var objFilter:Object = {property:entMode[1],operator:entities[1],p:entities[2]};
69 | if(objFilter.operator != "region" && objFilter.operator != "subset")
70 | if(objFilter.property == "size" ||objFilter.property == "mode"|| objFilter.property == "stime" || objFilter.property == "width" || objFilter.property == "height" || objFilter.property == "color" && objFilter.p.charAt(0)!="#"){
71 | objFilter.p=int(objFilter.p);
72 | }
73 | for(var m:int=0;mNumber(fdata.p)){
166 | return false;
167 | }
168 | return true;
169 | }
170 | case 'subset':
171 | case 'region':{
172 | if(fdata.property=="text" || fdata.property=="hash"){
173 | return true;
174 | }
175 | if(fdata.property=="color" && String(fdata.p).charAt(0)=="#"){
176 | //decode this color
177 | fdata.p = uint("0x" + String(fdata.p).substr(1,String(fdata.p).length));//numberd color
178 | }
179 | var limits:Array = String(fdata.p).split(",");
180 | if(cdata[fdata.property]!=null && Number(cdata[fdata.property])>Number(limits[0]) && Number(cdata[fdata.property])0){
94 | this._$container.removeChildAt(0);
95 | }
96 | }
97 | public function pause():void{
98 | this.isPlaying=false;
99 | for(var i:int = 0;i<_$container.numChildren;i++){
100 | var c:Comment = Comment(_$container.getChildAt(i));
101 | if(c!=null && c.effect!=null){
102 | c.effect.pause();
103 | }
104 | }
105 | }
106 | public function resume():void{
107 | for(var i:int = 0;i<_$container.numChildren;i++){
108 | var c:Comment = Comment(_$container.getChildAt(i));
109 | if(c!=null && c.effect!=null){
110 | c.effect.resume();
111 | }
112 | }
113 | this.isPlaying=true;
114 | }
115 | public function insert(commentData:Object):void{
116 | var obj:Object = {on:false};
117 | for (var key:String in commentData){
118 | obj[key] = commentData[key];
119 | }
120 | if(obj.border){
121 | this.start(obj);//only run if it is playing
122 | }
123 | if(obj.preview){
124 | return;//Don't really add for future plays
125 | }
126 | var p:int = binsert(this.timeline,obj,function(a:*,b:*):int{
127 | if(a.time < b.time)
128 | return -1;
129 | else
130 | {
131 | if(a.time > b.time){
132 | return 1;
133 | }else{
134 | if(a.date < b.date){
135 | return -1;
136 | }else if(a.date > b.date){
137 | return 1;
138 | }else{
139 | return 0;
140 | }
141 |
142 | }
143 | }
144 | });
145 | if(p <= this.position){
146 | this.position++;//inserted before so bump position up
147 | }
148 | }
149 | protected function start(data:Object):void{
150 | if(data.mode >= 6 && !this._$handleAdv){
151 | return;//Skip this
152 | }
153 | if(this._$cpuF && prepare_stack.length > 20){
154 | return;//skip it
155 | }
156 | data['on'] = false;
157 | //data['border']=true;
158 | var cmt:Comment = new Comment(data);
159 | cmt.defaults = this.cmSettings;
160 | //new comment
161 | var self:CommentManager = CommentManager(this);
162 | _$container.addChild(cmt);//add to container
163 | cmt.init();
164 | this.allocSpace(cmt);
165 | if(!this._$handleAdv){
166 | if(data.mode<4){
167 | var eff:Move = new Move(cmt);
168 | eff.easer = new Linear(0,0);
169 | eff.duration = 4000;
170 | eff.xFrom = _$container.width;
171 | eff.xTo = 0 - cmt.width;
172 | cmt.effect = eff;
173 | cmt.effect.play();
174 | }else if(data.mode==4 || data.mode==5){
175 | var eff2:Fade = new Fade(cmt);
176 | eff2.alphaTo = 1;
177 | eff2.alphaFrom = 1;
178 | eff2.duration = 4000;
179 | cmt.effect=eff2;
180 | cmt.effect.play();
181 | }else{
182 | trace('unknown mode!');
183 | }
184 | }else{
185 | if(data.mode==7 && this._$handleAdv){
186 | if(data.movable == false){
187 | var advFade:Fade = new Fade(cmt);
188 | advFade.alphaTo = data.outAlpha;
189 | advFade.alphaFrom = data.inAlpha;
190 | advFade.duration = data.duration * 1000;
191 | cmt.effect = advFade;
192 | cmt.effect.play();
193 | }else{
194 | trace("New Movable type Effect: " + data.toX + " " + data.toY + " DUR:" + data.moveDuration + " Delay:" + data.moveDelay);
195 | var advEvt:TimelineEffect = new TimelineEffect();
196 | var advFade2:Fade = new Fade(cmt);
197 | advFade2.alphaTo = data.outAlpha;
198 | advFade2.alphaFrom = data.inAlpha;
199 | advFade2.duration = data.duration * 1000;
200 | var advMove:Move = new Move(cmt);
201 | advMove.xTo = data.toX;
202 | advMove.yTo = data.toY;
203 | advMove.startDelay = data.moveDelay;
204 | advMove.duration = data.moveDuration;
205 | advEvt.addEffect(advFade2);
206 | advEvt.addEffect(advMove);
207 | cmt.effect = advEvt;
208 | cmt.effect.play();
209 | }
210 | }else if(data.mode==6 && this._$handleAdv){
211 | var effc:Move = new Move(cmt);
212 | effc.easer = new Linear(0,0);
213 | effc.duration = 4000;
214 | effc.xFrom = 0 - cmt.width;
215 | effc.xTo = _$container.width;
216 | cmt.effect = effc;
217 | cmt.effect.play();
218 | }
219 | }
220 | if(cmt.effect!=null){
221 | cmt.effect.addEventListener(EffectEvent.EFFECT_END,function ():void{
222 | self.complete(cmt);
223 | self.deallocSpace(cmt);
224 | self._$container.removeChild(cmt);
225 | cmt = null;
226 | });
227 | }else{
228 | this.complete(cmt);
229 | this.deallocSpace(cmt);
230 | this._$container.removeChild(cmt);
231 | cmt = null;//Free up space for comment
232 | return;//unhandled comments need not be pushed into run stack!
233 | //unhandled comment!;
234 | }
235 | this.prepare_stack.push(cmt);
236 | }
237 | protected function allocSpace(cm:Comment):void{
238 | if(cm.dataObject.mode<4){
239 | this.salloc_scroll.add(cm);
240 | }else if(cm.dataObject.mode==5){
241 | this.salloc_top.add(cm);
242 | }else if(cm.dataObject.mode==4){
243 | this.salloc_bottom.add(cm);
244 | }
245 | }
246 | protected function deallocSpace(cm:Comment):void{
247 | if(cm.dataObject.mode<4){
248 | this.salloc_scroll.remove(cm);
249 | }else if(cm.dataObject.mode==5){
250 | this.salloc_top.remove(cm);
251 | }else if(cm.dataObject.mode==4){
252 | this.salloc_bottom.remove(cm);
253 | }
254 | }
255 | protected function getComment(data:Object):Comment{
256 | return new Comment(data);
257 | }
258 | protected function complete(cmt:Comment):void{
259 | var i:int = this.prepare_stack.indexOf(cmt);
260 | this.prepare_stack.splice(i,1);//remove from current running
261 | }
262 | public function time(t:Number):void{
263 | if(!this.isPlaying){
264 | return;//not playing
265 | }
266 | t = t - 1;
267 | if(this.position >= this.timeline.length || Math.abs(this.lastPos - t) >= 2000){
268 | this.seek(t);
269 | this.clear();
270 | this.lastPos = t;
271 | if(this.timeline.length <= this.position){
272 | return;
273 | }
274 | }else{
275 | this.lastPos = t;
276 | }
277 | for(;this.position < this.timeline.length;this.position++){
278 | if(this.getData(this.position)['stime'] <= t){
279 | if(this.validate(this.getData(this.position))){
280 | this.start(this.getData(this.position));
281 | }
282 | }else{
283 | break;
284 | }
285 | }
286 | }
287 | protected function getData(id:int):Object{
288 | //safety wrapper
289 | if(id>=0 && id < this.timeline.length){
290 | return this.timeline[id];
291 | }
292 | return null;//npe
293 | }
294 | protected function seek(time:Number):void{
295 | this.position = bsearch(this._$list,time,function(pos:*,data:*):int{
296 | if(pos < data.stime){
297 | return -1;
298 | }else if(pos > data.stime){
299 | return 1;
300 | }else{
301 | return 0;
302 | }
303 | });
304 | }
305 | protected function validate(data:Object):Boolean{
306 | if(data['on']){
307 | return false;//dont send again
308 | }
309 | return _$filter.validate(data);//no filter caps yet!
310 | return true;
311 | }
312 | /**
313 | * BSearch
314 | **/
315 | public static function bsearch(arr:Array,a:*,f:Function):int{
316 | if(arr.length==0)
317 | return 0;//Nothing to search
318 | if(f(a,arr[0])<0)
319 | return 0;//Smaller than smallest
320 | if(f(a, arr[arr.length-1])>=0)
321 | return arr.length;//Bigger than biggest
322 | var low:int = 0;
323 | var i:int;
324 | var count:int = 0;
325 | var high:int = arr.length - 1;
326 | while(low<=high){
327 | i = Math.floor((high + low + 1)/2);//find middle
328 | count++;
329 | if(f(a,arr[i-1])>=0 && f(a,arr[i])<0){
330 | return i;
331 | }else if(f(a, arr[i-1]) < 0){
332 | high = i-1;
333 | }else if(f(a, arr[i]) >=0){
334 | low = i;
335 | }else{
336 | throw new Error("BSearch Unexpected Error");
337 | }
338 | if(count > 1500){
339 | throw new Error("BSearch Execute Limit Exceed");
340 | break;
341 | }
342 | }
343 | return -1;//Wha?
344 | }
345 | public static function binsert(arr:Array,elem:*,f:Function):Number{
346 | var i:int = bsearch(arr,elem,f);
347 | arr.splice(i,0,elem);
348 | return i;
349 | }
350 | }
351 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/CommentSpaceAllocator.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | /**
4 | * A Very Good Comment Space Allocator
5 | * @aristotle9 package mukioplayerplus
6 | * ported and edited for ABPlayer
7 | **/
8 | public class CommentSpaceAllocator
9 | {
10 | protected var pools:Array = new Array();
11 | protected var Width:int;
12 | protected var Height:int;
13 | public function CommentSpaceAllocator()
14 | {
15 | }
16 | public function setBounds(w:int,h:int):void{
17 | this.Width = w;
18 | this.Height = h;
19 | }
20 | public function add(cmt:Comment):void{
21 | cmt.x = (this.Width - cmt.width)/2;
22 | if(cmt.height >= this.Height){
23 | cmt.setY(0,-1,transformY);
24 | }else{
25 | //This needs calculation
26 | this.setY(cmt);
27 | }
28 | }
29 | public function setY(cmt:Comment,index:int = 0):void{
30 | var y:int =0;
31 | if(this.pools.length <= index){
32 | this.pools.push(new Array());
33 | }
34 | var pool:Array = this.pools[index];
35 | if(pool.length == 0){
36 | cmt.setY(0,index,transformY);
37 | pool.push(cmt);
38 | return;
39 | }
40 | if(this.vCheck(0,cmt,index)){
41 | cmt.setY(0,index,transformY);
42 | CommentManager.binsert(pool,cmt,bottom_cmp);
43 | return;
44 | }
45 | for each(var c:Comment in pool){
46 | y = c.bottom + 1;
47 | if(y + cmt.height > this.Height){
48 | break;
49 | }
50 | if(this.vCheck(y,cmt,index)){
51 | cmt.setY(y,index,transformY);
52 | CommentManager.binsert(pool,cmt,bottom_cmp);
53 | return;
54 | }
55 | }
56 | this.setY(cmt,index +1);
57 | }
58 | protected function transformY(y:int,c:Comment):int{
59 | return y;
60 | }
61 | protected function bottom_cmp(a:Comment,b:Comment):int{
62 | if(a.bottom bottom || c.bottom < y){
75 | continue;
76 | }else{
77 | return false;
78 | }
79 | }
80 | return true;
81 | }
82 | public function remove(cmt:Comment):void{
83 | if(cmt.index != -1){
84 | var pool:Array = this.pools[cmt.index];
85 | var n:int = pool.indexOf(cmt);
86 | pool.splice(n,1);
87 | }
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/ScrollCommentSpaceAllocator.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment
2 | {
3 | public class ScrollCommentSpaceAllocator extends CommentSpaceAllocator
4 | {
5 | private var dur:int = 4;
6 | public function ScrollCommentSpaceAllocator()
7 | {
8 | }
9 | override public function add(cmt:Comment):void
10 | {
11 | cmt.x = this.Width;
12 | cmt.duration = (this.Width + cmt.width) / this.getSpeed(cmt);
13 | if(cmt.height >= this.Height)
14 | {
15 | cmt.setY(0,-1,transformY);
16 | }
17 | else
18 | {
19 | this.setY(cmt);
20 | }
21 | }
22 | override protected function vCheck(y:int, cmt:Comment, index:int):Boolean
23 | {
24 | var bottom:int = y + cmt.height;
25 | var right:int = cmt.x + cmt.width;
26 | for each(var c:Comment in this.pools[index])
27 | {
28 | if(c.y > bottom || c.bottom < y)
29 | {
30 | continue;
31 | }
32 | else if(c.right < cmt.x || c.x > right)
33 | {
34 | if(this.getEnd(c) <= this.getMiddle(cmt))
35 | {
36 | continue;
37 | }
38 | else
39 | {
40 | return false;
41 | }
42 | }
43 | else
44 | {
45 | return false;
46 | }
47 | }
48 | return true;
49 | }
50 | private function getSpeed(cmt:Comment):Number
51 | {
52 | return 1 * 0.5 * (this.Width + cmt.width) / this.dur;
53 | }
54 | private function getEnd(cmt:Comment):Number
55 | {
56 | return cmt.stime + (this.Width + cmt.width) / this.getSpeed(cmt);
57 | }
58 | private function getMiddle(cmt:Comment):Number
59 | {
60 | return cmt.stime + this.Width / this.getSpeed(cmt);
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/org/kanoha/comment/effects/TimelineEffect.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.comment.effects
2 | {
3 | import mx.effects.Effect;
4 | import mx.effects.IEffectInstance;
5 | import mx.events.EffectEvent;
6 |
7 | import spark.effects.Animate;
8 |
9 | /***
10 | * Timelined Effect
11 | * @Package ABPlayer
12 | * A Special Effect for offsetting multiple effects together
13 | * **/
14 | public class TimelineEffect extends Animate
15 | {
16 | protected var _$eff:Array = new Array();
17 | protected var _$ran:int = 0;
18 | public function TimelineEffect()
19 | {
20 | }
21 | public function addEffect(eff:Animate):void{
22 | this._$eff.push(eff);
23 | }
24 | public function removeEffect(eff:Animate):void{
25 | var rid:int = this._$eff.indexOf(eff);
26 | this._$eff.splice(rid,1);
27 | }
28 | private function onEffectEnd(e:EffectEvent):void{
29 | this._$ran++;
30 | trace(_$ran);
31 | if(_$ran==_$eff.length){
32 | this.dispatchEvent(new EffectEvent(EffectEvent.EFFECT_END));
33 | trace("Multiple Effect Finished");
34 | }
35 | }
36 | override public function end(inst:IEffectInstance = null):void{
37 | //End all effects
38 | for(var i:int = 0;i<_$eff.length;i++){
39 | if(_$eff[i]!=null && Effect(_$eff[i]).isPlaying)
40 | _$eff[i].end();
41 | }
42 | //The end dispatch event will be automatically dispatched
43 | }
44 | override public function resume():void{
45 | for(var i:int = 0;i<_$eff.length;i++){
46 | if(_$eff[i]!=null && Effect(_$eff[i]).isPlaying)
47 | _$eff[i].resume();
48 | }
49 | }
50 | override public function pause():void{
51 | for(var i:int = 0;i<_$eff.length;i++){
52 | if(_$eff[i]!=null && Effect(_$eff[i]).isPlaying)
53 | _$eff[i].pause();
54 | }
55 | }
56 | override public function play(targets:Array=null,reverse:Boolean=false):Array{
57 | //Get count
58 | if(this._$eff.length ==0){
59 | this.dispatchEvent(new EffectEvent(EffectEvent.EFFECT_END));//Nothing to do
60 | return null;
61 | }
62 | for(var i:int=0;iq && int(video.attribute("brt"))<=4){
48 | q = int(video.attribute("brt"));//find highest quality
49 | v = video.toString();
50 | }
51 | }
52 | var tdInfo:VideoInfo = new VideoInfo(v,uint(xmlObj.attribute("time")),0);
53 | return {video:[tdInfo],duration:uint(xmlObj.attribute("time"))};
54 | }else{
55 | return {};
56 | }
57 | }
58 | private function onError():void{
59 | trace('An error occurred');
60 | }
61 | }
62 | }
--------------------------------------------------------------------------------
/src/org/kanoha/net/XMLLoader.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.net
2 | {
3 | import flash.events.Event;
4 | import flash.events.EventDispatcher;
5 | import flash.net.URLLoader;
6 | import flash.net.URLRequest;
7 | import flash.events.IOErrorEvent;
8 | import org.kanoha.events.LoaderEvent;
9 | public class XMLLoader extends EventDispatcher
10 | {
11 | private var loader:URLLoader = new URLLoader();
12 | public function XMLLoader()
13 | {
14 | this.hookListeners();
15 | }
16 | public function load(url:String):void{
17 | var req:URLRequest = new URLRequest(url);
18 | loader.load(req);
19 | }
20 | private function hookListeners():void{
21 | loader.addEventListener(Event.COMPLETE,onComplete);
22 | loader.addEventListener(IOErrorEvent.IO_ERROR,onError);
23 | }
24 | private function onComplete(e:Event):void{
25 | try{
26 | var xml:XML = new XML(loader.data);
27 | this.dispatchEvent(new LoaderEvent(LoaderEvent.XML_COMPLETE,xml));
28 | }catch(e:Error){
29 | this.dispatchEvent(new LoaderEvent(LoaderEvent.XML_PARSE_ERROR));
30 | }
31 | }
32 | private function onError():void{
33 | this.dispatchEvent(new LoaderEvent(LoaderEvent.XML_LOAD_ERROR));
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/org/kanoha/util/CommentListParser.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.util
2 | {
3 | public class CommentListParser
4 | {
5 | public function CommentListParser()
6 | {
7 | }
8 | public static function parse(input:XML,mode:int = 0):Array{
9 | if(mode==0){
10 | return CommentListParser.AvXML2Comment(input);
11 | }
12 | return new Array();
13 | }
14 | public static function AvXML2Comment(input:XML):Array{
15 | var ret:Array=new Array();
16 | var tmp:XMLList = input.d;
17 | var id:int = 0;
18 | for each(var nd:XML in tmp){
19 | var p:Array = String(nd.@p).split(',');
20 | var text:String = String(nd);
21 | var obj:Object = {};
22 | obj.stime = uint(parseFloat(p[0])*1000);
23 | obj.size = uint(p[2]);
24 | obj.color = uint(p[3]);
25 | obj.mode = uint(p[1]);
26 | obj.date = new Date(p[4] * 1000);
27 | obj.timestamp = int(p[4]);
28 | obj.pool = uint(p[5]);
29 | obj.hash = p[6];
30 | obj.border = false;
31 | obj.id = id ++;
32 | if(obj.mode<7){
33 | obj.text = text.replace(/(\/n|\\n|\n|\r\n)/g, "\r");
34 | }else{
35 | if(obj.mode==7){
36 | try{
37 | var json:Object = JSON.parse(text);
38 | obj.x = Number(json[0]);
39 | obj.y = Number(json[1]);
40 | obj.text = String(json[4]).replace(/(\/n|\\n|\n|\r\n)/g, "\r");
41 | obj.rZ = 0;
42 | obj.rY = 0;
43 | if(json.length >= 7){
44 | obj.rZ = Number(json[5]);
45 | obj.rY = Number(json[6]);
46 | }
47 | obj.movable = false;
48 | //insert advanced mode here
49 | if(json.length >=11){
50 | obj.movable = true;
51 | obj.toX = Number(json[7]);
52 | obj.toY = Number(json[8]);
53 | obj.moveDuration = 500;
54 | obj.moveDelay = 0;
55 | if(json[9]!='')
56 | obj.moveDuration = Number(json[9]);
57 | if(json[10]!='')
58 | obj.moveDelay = Number(json[10]);
59 | }
60 | obj.duration = 2.5;
61 | if(json[3] < 12 && json[3] != 1){
62 | obj.duration = Number(json[3]);
63 | }
64 | obj.inAlpha = 1;
65 | obj.outAlpha = 1;
66 | var a:Array = String(json[2]).split('-');
67 | if(a.length >=2){
68 | obj.inAlpha = Number(a[0]);
69 | obj.outAlpha = Number(a[1]);
70 | }
71 | }catch(e:Error){
72 | trace('JSON Failed!?');
73 | trace(text);
74 | }
75 | }else{
76 | obj.text = 'Advanced not supported!';
77 | }
78 | }
79 | ret.push(obj);
80 | }
81 | return ret;
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/org/kanoha/util/Filters.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.util
2 | {
3 | import flash.filters.GlowFilter;
4 | public class Filters
5 | {
6 | private static var fs:Array = [new GlowFilter(0,1,6,6,5)];
7 | private static var fs2:Array = [new GlowFilter(0, 0.7, 3,3)];
8 | public function Filters()
9 | {
10 |
11 | }
12 | public static function getGlow():Array{
13 | return fs;
14 | }
15 | public static function getAdvancedGlow():Array{
16 | return fs2;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/org/kanoha/video/NS.as:
--------------------------------------------------------------------------------
1 | package org.kanoha.video
2 | {
3 | import flash.events.*;
4 | import flash.media.*;
5 | import flash.net.*;
6 | import flash.utils.Timer;
7 |
8 | import org.kanoha.events.NSEvent;
9 | public class NS extends EventDispatcher
10 | {
11 | private var _$id:uint;
12 | private var _$stopSign:Boolean;
13 | private var _$bufferTime:uint;
14 | private var _$nc:NetConnection;
15 | private var _$ns:NetStream;
16 | private var _$is_hc:Boolean;
17 | private var _$isStop:Boolean;
18 | private var _$checkPolicyFile:Boolean = false;
19 | private var _$volume:Number = 0.7;
20 | private var _$btimer:Timer = new Timer(100);
21 | private var _$ptimer:Timer = new Timer(10);
22 | private var _$isLoad:Boolean = false;
23 | public function NS(bufferTime:uint = 5) : void
24 | {
25 | _$bufferTime = bufferTime;
26 | init();
27 | return;
28 | }
29 | private function init() : void
30 | {
31 | this.addEventListener(NSEvent.CHECK_FULL,onReallyFull)
32 | _$btimer.addEventListener(TimerEvent.TIMER,checkBuff)
33 | _$ptimer.addEventListener(TimerEvent.TIMER,onPlaying)
34 | _$nc = new NetConnection();
35 | _$nc.addEventListener(NetStatusEvent.NET_STATUS, ncStatus);
36 | _$nc.connect(null);
37 | return;
38 | }
39 | private function onPlaying(eve:TimerEvent):void
40 | {
41 | dispatchEvent(new NSEvent(NSEvent.PLAYING,this.time));
42 | }
43 | private function checkBuff(eve:TimerEvent):void
44 | {
45 | dispatchEvent(new NSEvent(NSEvent.BUFFERING,this.loadPercent));
46 | if(this.loadPercent == 1)
47 | {
48 | trace("really full!")
49 | dispatchEvent(new NSEvent(NSEvent.CHECK_FULL));
50 | this.removeEventListener(TimerEvent.TIMER,checkBuff);
51 | this._$btimer.stop();
52 | this._$isLoad = true
53 | }
54 | }
55 |
56 | private function ncStatus(param1:NetStatusEvent) : void
57 | {
58 | if (param1.info.code == "NetConnection.Connect.Success")
59 | {
60 | createNS();
61 | }
62 | return;
63 | }
64 | private function createNS():void
65 | {
66 | _$ns = new NetStream(_$nc);
67 | _$ns.bufferTime = _$bufferTime;
68 | _$ns.client = this;
69 | if(this._$checkPolicyFile){
70 | _$ns.checkPolicyFile = true;
71 | }
72 | setVolume();
73 | removeEvent(_$ns);
74 | addEvent(_$ns);
75 | return;
76 | }
77 |
78 | public function set id(param1:uint) : void
79 | {
80 | _$id = param1;
81 | return;
82 | }
83 | public function stopV() : void
84 | {
85 | _$ptimer.stop();
86 | _$btimer.stop();
87 | _$ns.pause();
88 | _$ns.seek(0);
89 | return;
90 | }
91 | public function closeV() : void
92 | { _$ptimer.stop();
93 | _$btimer.stop();
94 | _$ns.pause();
95 | _$ns.close();
96 | return;
97 | }
98 | public function pauseV() : void
99 | {
100 | _$ptimer.stop();
101 | _$ns.pause();
102 | return;
103 | }
104 | public function get volume() : Number
105 | {
106 | return _$volume;
107 | }
108 | private function setVolume(param1:Number = 0.7) : void
109 | {
110 | _$volume = param1;
111 | var st:SoundTransform = new SoundTransform(_$volume, 0);
112 | _$ns.soundTransform = st;
113 | return;
114 | }
115 | public function seekV(param1:Number) : void
116 | {
117 | param1 = Math.floor(param1 / 1000);
118 | _$ns.seek(param1);
119 | return;
120 | }
121 | public function playV() : void
122 | {
123 | _$ptimer.start();
124 | if(!_$isLoad)
125 | _$btimer.start();
126 | _$isStop = false;
127 | _$ns.resume();
128 | return;
129 | }
130 | private function asyncHandler(param1:AsyncErrorEvent) : void
131 | {
132 | trace("AsyncErrorEvent::" + param1.type);
133 | return;
134 | }
135 | public function loadV(param1:String) : void
136 | {
137 | var path:String = param1;
138 | _$isStop = false;
139 | _$is_hc = false;
140 | _$stopSign = false;
141 | try
142 | {
143 | _$ns.play(path);
144 | }// end try
145 | catch (e:Error)
146 | {
147 | trace(e);
148 | }// end catch
149 | _$ns.pause();
150 | this._$btimer.start()
151 | return;
152 | }
153 | private function addEvent(dispather:NetStream) : void
154 | {
155 | dispather.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
156 | dispather.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncHandler);
157 | return;
158 | }
159 | private function removeEvent(param1:NetStream) : void
160 | {
161 | param1.removeEventListener(NetStatusEvent.NET_STATUS, statusHandler);
162 | param1.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncHandler);
163 | return;
164 | }
165 |
166 | private function statusHandler(param1:NetStatusEvent) : void
167 | {
168 | var loadPercent:Number;
169 | var info:String = param1.info.code;
170 | // trace("stream state:" + info);
171 | switch(info)
172 | {
173 | case "NetStream.Play.Start":
174 | {
175 | dispatchEvent(new NSEvent(NSEvent.READY));
176 | break;
177 | }// end case
178 | case "NetStream.Play.Stop": //break playing
179 | {
180 | if (!_$isStop)//is playing
181 | {
182 | _$isStop = true;
183 | trace("stopStop");
184 | dispatchEvent(new NSEvent(NSEvent.STOP));
185 | }// end if
186 | break;
187 | }// end case
188 | case "NetStream.Buffer.Empty":
189 | {
190 | if (_$stopSign)// is buffer flushed
191 | {
192 | if (!_$isStop)//is playing
193 | {
194 | _$isStop = true;//stopped
195 | trace("emptyStop");
196 | dispatchEvent(new NSEvent(NSEvent.STOP));
197 | }// end if
198 | }
199 | else //it's not really the end..wait for buffering...
200 | {
201 | loadPercent = Math.round(_$ns.bufferLength / _$ns.bufferTime * 100) / 100;
202 | dispatchEvent(new NSEvent(NSEvent.EMPTY, loadPercent));
203 | }// end else if
204 | break;
205 | }// end case
206 | case "NetStream.Buffer.Full":
207 | {
208 | if (!_$is_hc)
209 | {
210 | _$is_hc = true;//firsttime start playing?
211 | dispatchEvent(new NSEvent(NSEvent.PLAY));
212 | }
213 | else
214 | {
215 | dispatchEvent(new NSEvent(NSEvent.FULL));
216 | }// end else if
217 | break;
218 | }// end case
219 | case "NetStream.Buffer.Flush":
220 | { //buffer will be clear
221 | if (!_$stopSign) //set buffer stop sign
222 | {
223 | _$stopSign = true;
224 | }// end if
225 | dispatchEvent(new NSEvent(NSEvent.FLUSH));
226 | break;
227 | }// end case
228 | case "NetStream.Play.StreamNotFound":
229 | {
230 | trace("StreamNotFound");
231 | dispatchEvent(new NSEvent(NSEvent.FILE_EMPTY));
232 | break;
233 | }// end case
234 | case "NetStream.Seek.Notify":
235 | {
236 | //seek completed set is flush false
237 | _$stopSign = false;
238 | break;
239 | }// end case
240 | case "NetStream.Seek.Failed":
241 | {
242 | break;
243 | }// end case
244 | case "NetStream.Seek.InvalidTime":
245 | {
246 | dispatchEvent(new NSEvent(NSEvent.SEEK_ERROR));
247 | break;
248 | }// end case
249 | default:
250 | {
251 | break;
252 | }// end default
253 | }// end switch
254 | return;
255 | }// end function
256 | public function get ns() : NetStream
257 | {
258 | return _$ns;
259 | }
260 | public function get loadPercent() : Number
261 | {
262 | return _$ns.bytesLoaded / _$ns.bytesTotal;
263 | }
264 | public function get total() : Number
265 | {
266 | return _$ns.bytesTotal;
267 | }
268 | public function get loaded() : Number
269 | {
270 | return _$ns.bytesLoaded;
271 | }
272 | public function get time() : Number
273 | {
274 | var time:uint = Math.round(_$ns.time * 1000);
275 | return time;
276 | }
277 | public function set volume(param1:Number) : void
278 | {
279 | param1 = param1 > 1 ? (1) : (param1);
280 | param1 = param1 < 0 ? (0) : (param1);
281 | setVolume(param1);
282 | return;
283 | }
284 | public function set checkPolicyFile(check:Boolean):void{
285 | this._$checkPolicyFile;
286 | }
287 | public function get id() : uint
288 | {
289 | return _$id;
290 | }
291 | public function get bufferTime() : int
292 | {
293 | return _$bufferTime;
294 | }
295 | public function set bufferTime(param1:int) : void
296 | {
297 | _$bufferTime = param1;
298 | _$ns.bufferTime = param1;
299 | return;
300 | }
301 | public function onMetaData(param1:Object) : void
302 | {
303 | dispatchEvent(new NSEvent(NSEvent.META_DATA, param1));
304 | return;
305 | }
306 | public function onCuePoint(param1:Object) : void
307 | {
308 | trace("cue point" + param1);
309 | return;
310 | }
311 | public function onLastSecond(param1:Object):void
312 | {
313 | trace("last second" + param1);
314 | }
315 | public function onReallyFull(param1:NSEvent):void
316 | {
317 | this._$btimer.stop()
318 | }
319 | public function onXMPData(param1:Object):void{
320 | return;
321 | }
322 | }
323 | }
--------------------------------------------------------------------------------
/src/org/kanoha/video/NSComponent.as:
--------------------------------------------------------------------------------
1 | /*******************
2 | * Based on Tamaki Video Component
3 | * Modified by CQZ
4 | * 2011-9-3 Initial
5 | ********************/
6 | package org.kanoha.video
7 | {
8 | import flash.events.Event;
9 | import flash.filters.ColorMatrixFilter;
10 | import flash.media.Video;
11 |
12 | import mx.core.UIComponent;
13 | import mx.events.ResizeEvent;
14 |
15 | import org.kanoha.events.*;
16 | public class NSComponent extends UIComponent
17 | {
18 | private var nss:Array; //netstreams
19 | private var ifs:Array; //videoinfo
20 | private var ofs:Array; //offset:uint
21 | private var bi:int; //buffer index
22 | private var pi:int;//play index
23 | private var _$volume:Number;
24 | private var _$video:Video;
25 | private var _$total:uint;
26 | private var _$state:String = NSComponent.UNLOAD;
27 | private var _$smoothing:Boolean;
28 | private var _$metaReader:NS;
29 | private var _$url:String;
30 | private var _$allowScreencap:Boolean = true;
31 | public static const UNLOAD:String = "unLoad";
32 | public static const PLAY:String = "play";
33 | public static const STOP:String = "stop";
34 | public static const PAUSE:String = "pause";
35 | public var p_x:int = 0;
36 | public var p_y:int = 0;
37 | public var nsBuf:Boolean=false;
38 | public function NSComponent()
39 | {
40 | super();
41 | this._$video = new Video();
42 | this.addChild(this._$video);
43 | this._$video.height = this.height;
44 | this._$video.width = this.width;
45 | this.addEventListener(ResizeEvent.RESIZE,resize);
46 | this.addEventListener(NMEvent.COMPLETE,onComplete);
47 | }
48 | public function resize(eve:Event):void
49 | {
50 | if(this._$video==null)
51 | return;//dont resize if video not inited
52 | if(this.p_x<=0 || this.p_y<=0){
53 | this._$video.width = this.width;
54 | this._$video.height = this.height;
55 | }else{
56 | if((this.width / this.height) >= (this.p_x / this.p_y)){
57 | this._$video.height = this.height;
58 | this._$video.width = (this.height * this.p_x )/this.p_y;
59 | }else{
60 | this._$video.width = this.width;
61 | this._$video.height = (this.width * this.p_y)/ this.p_x;
62 | }
63 | //Position Center
64 | this._$video.x = (this.width - this._$video.width)/2;
65 | this._$video.y = (this.height - this._$video.height)/2;
66 | }
67 | }
68 | public function init(ifv:Array,tv:uint):void
69 | {
70 | this.close();
71 | this.resetAll();
72 | this.ifs = ifv;
73 | this._$total = tv;
74 | initOffset();
75 | createBuffer();
76 | }
77 | public function initBySingleUrl(url:String):void
78 | {
79 | this.close();
80 | this.resetAll();
81 | this._$url = url;
82 | this._$metaReader = new NS();
83 | this._$metaReader.addEventListener(NSEvent.META_DATA,onMetaData);
84 | this._$metaReader.loadV(url);
85 | this.addEventListener(NMEvent.META_LOADED,onMetaLoaded);
86 | }
87 | private function onMetaLoaded(eve:NMEvent):void
88 | {
89 | initOffset();
90 | trace('loaded meta!');
91 | createBuffer();
92 | this.dispatchEvent(new NMEvent(NMEvent.URL_COMPLETE));
93 | }
94 | private function initOffset():void
95 | {
96 | var co:uint = 0;
97 | for(var i:uint = 0;i < ifs.length;i++)
98 | {
99 | ofs[i] = co += VideoInfo(ifs[i]).length;
100 | }
101 | }
102 | private function createBuffer():void
103 | {
104 | if(ifs[++bi])
105 | {
106 | var ns:NS = new NS();
107 | var info:VideoInfo = VideoInfo(ifs[bi]);
108 | if(this._$allowScreencap){
109 | ns.checkPolicyFile = true;
110 | }
111 | ns.id = info.id;
112 | ns.loadV(info.url);
113 | ns.addEventListener(NSEvent.META_DATA,onSingleMetaData);
114 | ns.addEventListener(NSEvent.STOP, onStop);
115 | ns.addEventListener(NSEvent.CHECK_FULL, onFull);
116 | ns.addEventListener(NSEvent.BUFFERING,onBuff);
117 | ns.addEventListener(NSEvent.PLAYING,onPlaying);
118 | ns.addEventListener(NSEvent.FILE_EMPTY,onNotFound);
119 | ns.volume = this._$volume;
120 | nss.push(ns);
121 | }
122 | }
123 | private function changeNS():void
124 | {
125 | if(pi >= 0)
126 | {
127 | if(!nss[pi])
128 | return;
129 | NS(nss[pi]).stopV();
130 | }
131 | if(nss[pi+1])
132 | {
133 | NS(nss[++pi]).playV();
134 | NS(nss[pi]).stopV();
135 | NS(nss[pi]).playV();
136 | this.attachVideo(_$video);
137 | }
138 | }
139 | private function onFull(eve:NSEvent):void
140 | {
141 | if(this.state != NSComponent.UNLOAD)
142 | {
143 | if(nss[bi]!=null){
144 | NS(nss[bi]).removeEventListener(NSEvent.BUFFERING,onBuff);
145 | NS(nss[bi]).removeEventListener(NSEvent.CHECK_FULL,onFull);
146 | }
147 | createBuffer();
148 | }
149 | }
150 | private function onStop(eve:NSEvent):void
151 | {
152 | if(pi != ifs.length-1)
153 | changeNS();
154 | else
155 | {
156 | this.dispatchEvent(new NMEvent(NMEvent.COMPLETE));
157 | }
158 | }
159 | private function onBuff(eve:NSEvent):void
160 | {
161 | var current:Number;
162 | var next:Number
163 | if(bi == 0)
164 | {
165 | next = ofs[bi]/_$total;
166 | current = Number(eve.info) * next;
167 | this.dispatchEvent(new NMEvent(NMEvent.PROGRESS,current));
168 | }
169 | else
170 | {
171 | var pre:Number = ofs[bi-1]/_$total;
172 | next = ofs[bi]/_$total;
173 | current = pre + Number(eve.info) * (next - pre);
174 | this.dispatchEvent(new NMEvent(NMEvent.PROGRESS,current));
175 | }
176 | }
177 | private function onPlaying(eve:NSEvent):void
178 | {
179 | if(pi == 0)
180 | this.dispatchEvent(new NMEvent(NMEvent.PLAY_HEAD_UPDATE,uint(eve.info)));
181 | else
182 | {
183 | this.dispatchEvent(new NMEvent(NMEvent.PLAY_HEAD_UPDATE,uint(ofs[pi-1]+uint(eve.info))));
184 | }
185 | }
186 | private function onNotFound(eve:NSEvent):void
187 | {
188 | this.dispatchEvent(new NMEvent(NMEvent.VIDEO_NOT_FOUND))
189 | }
190 | private function getPIByTime(time:uint):uint
191 | {
192 | var i:uint = 0;
193 | var pre:uint = 0;
194 | for(;i pre && time <= ofs[i])
197 | break;
198 | pre = ofs[i++];
199 | }
200 | return i;
201 | }
202 | private function seekInPart(time:uint,si:uint):void
203 | {
204 | var ptime:uint;
205 | if (si == 0)
206 | ptime = time;
207 | else
208 | ptime = time - ofs[si-1];
209 | NS(nss[pi]).seekV(ptime);
210 | this.play();
211 | }
212 | private function attachVideo(v:Video):void
213 | {
214 | //v.clear();
215 | v.attachNetStream(NS(nss[pi]).ns);
216 | }
217 | private function onSingleMetaData(eve:NSEvent):void{
218 | if(!nsBuf){
219 | nsBuf = true;
220 | }else{
221 | return;
222 | }
223 | if(eve.info.width!=null && eve.info.height!=null){
224 | this.p_x = eve.info.width;
225 | this.p_y = eve.info.height;
226 | this.resize(null);
227 | }
228 | if(nss != null && nss[bi]!=null )
229 | NS(this.nss[bi]).removeEventListener(NMEvent.META_LOADED,onSingleMetaData);
230 | this.dispatchEvent(new NMEvent(NMEvent.META_LOADED,eve.info));
231 | }
232 | private function onMetaData(eve:NSEvent):void
233 | {
234 | if(eve.info.width!=null && eve.info.height!=null){
235 | this.p_x = eve.info.width;
236 | this.p_y = eve.info.height;
237 | this.resize(null);
238 | }
239 | this._$total = eve.info.duration * 1000;
240 | this.ifs = new Array;
241 | this.ifs.push(new VideoInfo(this._$url,eve.info.duration *1000));
242 | this._$metaReader.removeEventListener(NSEvent.META_DATA,onMetaData);
243 | this._$metaReader.closeV();
244 | this._$metaReader = null;
245 | this.dispatchEvent(new NMEvent(NMEvent.META_LOADED,eve.info));
246 | }
247 | private function resetAll():void
248 | {
249 | if(nss&&nss[bi])
250 | {
251 | NS(nss[bi]).removeEventListener(NSEvent.BUFFERING,onBuff);
252 | NS(nss[bi]).removeEventListener(NSEvent.CHECK_FULL,onFull);
253 | }
254 | this.bi = -1;
255 | this.pi = -1;
256 | this._$volume = 0.7;
257 | this.nss = new Array();
258 | this.ofs = new Array();
259 | this._$state = NSComponent.UNLOAD;
260 | }
261 | private function onComplete(eve:NMEvent):void
262 | {
263 | this.stop();
264 | this.play();
265 | this.stop();
266 | this.dispatchEvent(new NMEvent(NMEvent.REFRESH));
267 | }
268 | /*** Handlers ***/
269 | public function seek(time:uint):Boolean
270 | {
271 | if(this._$state == NSComponent.STOP||this._$state == NSComponent.UNLOAD)
272 | return false;
273 | var si:uint = this.getPIByTime(time);
274 | if(si >= nss.length)
275 | si = nss.length-1;
276 | if(si == pi)
277 | {
278 | this.seekInPart(time,si);
279 | }
280 | else
281 | {
282 | this.stop();
283 | pi = si;
284 | this.attachVideo(this._$video);
285 | this.seekInPart(time,si);
286 | }
287 | return true;
288 | }
289 | public function play():Boolean
290 | {
291 | if(this._$state == NSComponent.PLAY)
292 | return false;
293 | if(pi == -1)
294 | changeNS();
295 | else
296 | NS(nss[pi]).playV();
297 | this.dispatchEvent(new NMEvent(NMEvent.STATE_CHANGE,"play"));
298 | this._$state = NSComponent.PLAY;
299 | return true;
300 | }
301 | public function pause():Boolean
302 | {
303 | if(this._$state != NSComponent.PLAY)
304 | return false;
305 | if(nss==null || nss[pi]==null){
306 | //not prepared
307 | return false;
308 | }
309 | NS(nss[pi]).pauseV();
310 | this.dispatchEvent(new NMEvent(NMEvent.STATE_CHANGE,"pause"));
311 | this._$state = NSComponent.PAUSE;
312 | return true;
313 | }
314 | public function stop():Boolean
315 | {
316 | if(this._$state == NSComponent.STOP||this._$state==NSComponent.UNLOAD)
317 | return false
318 | for(var i:uint = 0;i
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnCommentOnSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnFullScreenSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnMuteSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnPauseSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnPlaySkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnSidebarOffSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnSidebarOnSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnSmallScreenSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnStopSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/btnVolumeSkin.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/skins/containerBar.mxml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------