diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 389d9e8f..00000000 --- a/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -/client/output -/client/libs/api.swc -/release -/server/.idea -/server/build -/client/.metadata diff --git a/README b/README deleted file mode 100644 index e03064b2..00000000 --- a/README +++ /dev/null @@ -1,4 +0,0 @@ -Flashphoner-client is an open-source part of Flashphoner product. -You can use it for customization. - -Builds: http://flashphoner.com/downloads/builds/flashphoner_client/ \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100644 index e4b7e762..00000000 --- a/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -FULL_PATH=$0 -CURRENT_DIR=`dirname $FULL_PATH` -cd $CURRENT_DIR -cd builder -chmod +x builder.sh -./builder.sh \ No newline at end of file diff --git a/builder/builder.sh b/builder/builder.sh deleted file mode 100644 index 776daed9..00000000 --- a/builder/builder.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh -. ./functions.lib - -cd $CURRENT_DIR - -echo "" > log -# check_root_access -# detect_java -# detect_ant - -echo "Start clients build..." -build_client "$CURRENT_DIR/../" -echo "Build clients complete" -echo "" -# echo "Start server build..." -# cd "$CURRENT_DIR/../$BUILD_XML_DIR" -# ant -# -# echo "Build server complete" -# echo "" - -cd "$CURRENT_DIR/../release" - -FOLDER_NAME=$(ls) - -echo "Creating archive of the build" -tar -cvf $FOLDER_NAME.tar.gz $FOLDER_NAME >& /dev/null -echo "FINISH" - diff --git a/builder/functions.lib b/builder/functions.lib deleted file mode 100644 index 4860491a..00000000 --- a/builder/functions.lib +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/sh -CURRENT_DIR=`pwd` -FLASHPHONER_API_DIR="client/api" -FLASHPHONER_CLIENT_DIR="client/client" -BUILD_XML_DIR="server/phone_app" - -check_root_access(){ - USERID=`id | sed -e 's/).*//; s/^.*(//;'` - if [ "X$USERID" != "Xroot" ]; then - echo "" - echo "ERROR: You must be logged in as the root user to install the Flashphoner." - echo "" - exit - fi -} - -detect_java(){ - echo "DETECTING java command..." - - JAVA_SYMLINK_BIN=`which java 2>/dev/null` - if ! test -f "$JAVA_SYMLINK_BIN" ; then - echo "" - echo "ERROR: The Java command (java) could not be found." - echo "Search path: $PATH" - echo "In most cases this problem can be fixed by adding a symbolic " - echo "link to the Java command in the /usr/bin directory. " - echo "To do this first execute the command \"which java\" to identify " - echo "the full path to the Java executable. Next, create a symbolic " - echo "link to this file with the command" - echo "\"ln -sf [path-to-java] /usr/bin/java\" where [path-to-java] is " - echo "the path returned by the \"which\" command." - echo "" - exit 0 - else - echo "- Java command found successfully." - fi - echo "" - - echo "DETECTING JVM architecture..." - java -version 2> tmp.jdk-version 1> /dev/null - JDK_VERSION=`cat tmp.jdk-version` - rm tmp.jdk-version - JVM_ARCH=`echo $JDK_VERSION | sed 's/.*\(...bit\).*/\1/i'` - JVM_ARCH_DIGIT=`echo $JVM_ARCH | sed 's/\([0-9]*\).*/\1/'` - echo "- $JVM_ARCH architecture detected successfully." - echo "" - - echo "DETECTING JDK home..." - JAVA_SYMLINK=`ls -l $JAVA_SYMLINK_BIN` - JDK_BIN=`echo $JAVA_SYMLINK | sed 's/.*->//'` - JDK_HOME=`echo $JDK_BIN | sed 's/\/bin.*//'` - if [ ! -f $JDK_HOME/include/jni.h ]; then - echo "- Can not find jni.h in JDK_HOME/include dir." - get_jdk_home () { - echo "- Please specify JDK_HOME path manually. File JDK_HOME/include/jni.h must exist." - read in - if [ ! -z "$in" ]; then - if [ ! -f $in/include/jni.h ]; then - echo "- Can not find jni.h in JDK_HOME/include dir." - get_jdk_home - fi - JDK_HOME=$in - echo "- JDK home detected successfully: $JDK_HOME" - else - echo "- Please do not enter a blank JDK home." - get_jdk_home - fi - } - get_jdk_home - else - echo "- JDK home detected successfully: $JDK_HOME." - fi - echo "" -} - -detect_ant(){ - echo "DETECTING ANT..." - - ANT_RESPONSE=$(ant 2>&1 | grep Buildfile) - if [ ! -n "$ANT_RESPONSE" ]; then - echo "- Error: ANT is not found" - exit - fi - echo "- ANT detected successfully." - echo "" -} - -build_client(){ - cd "$1$FLASHPHONER_API_DIR" - BUILD_RESPONSE=$(ant 2>&1 |tee -a $CURRENT_DIR"/log" 2>&1 | grep -i FAILED) - if [ -n "$BUILD_RESPONSE" ]; then - echo "Error. Build api was not created" - exit 0 - else - cd "$1$FLASHPHONER_CLIENT_DIR" - BUILD_RESPONSE=$(ant 2>&1|tee -a $CURRENT_DIR"/log" 2>&1 | grep -i FAILED) - if [ -n "$BUILD_RESPONSE" ]; then - echo "Error. Build client was not created" - exit 0 - else - echo "Build client has been created" - fi - fi -} diff --git a/client/api/.actionScriptProperties b/client/api/.actionScriptProperties deleted file mode 100644 index 4e4f3186..00000000 --- a/client/api/.actionScriptProperties +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/client/api/.flexLibProperties b/client/api/.flexLibProperties deleted file mode 100644 index f38e47d4..00000000 --- a/client/api/.flexLibProperties +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/api/.project b/client/api/.project deleted file mode 100644 index 5ff1b301..00000000 --- a/client/api/.project +++ /dev/null @@ -1,25 +0,0 @@ - - - api - - - - - - com.adobe.flexbuilder.project.flexbuilder - - - - - - com.adobe.flexbuilder.project.flexlibnature - com.adobe.flexbuilder.project.actionscriptnature - - - - bin-debug - 2 - DOCUMENTS/libs - - - diff --git a/client/api/.settings/org.eclipse.core.resources.prefs b/client/api/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 93de40f2..00000000 --- a/client/api/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Wed Aug 18 17:12:19 NOVST 2010 -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/client/api/.settings/org.eclipse.wst.html.core.prefs b/client/api/.settings/org.eclipse.wst.html.core.prefs deleted file mode 100644 index ba47ee12..00000000 --- a/client/api/.settings/org.eclipse.wst.html.core.prefs +++ /dev/null @@ -1,36 +0,0 @@ -#Wed Aug 18 17:18:46 NOVST 2010 -attrDuplicate=2 -attrInvalidName=2 -attrInvalidValue=2 -attrNameMismatch=2 -attrUndefName=2 -attrUndefValue=2 -attrValueMismatch=1 -attrValueUnclosed=2 -cdataInvalidContent=2 -cdataUnclosed=1 -commentInvalidContent=2 -commentUnclosed=1 -docDoctypeUnclosed=1 -docDuplicateTag=1 -docInvalidChar=2 -docInvalidContent=2 -eclipse.preferences.version=1 -elemCoexistence=2 -elemDuplicate=2 -elemEndInvalidCase=1 -elemInvalidContent=2 -elemInvalidDirective=1 -elemInvalidEmptyTag=2 -elemInvalidName=1 -elemMissingEnd=2 -elemMissingStart=1 -elemStartInvalidCase=2 -elemUnclosedEndTag=1 -elemUnclosedStartTag=1 -elemUnknownName=2 -elemUnnecessaryEnd=2 -piInvalidContent=2 -piUnclosed=1 -piUndefined=2 -refInvalidContent=2 diff --git a/client/api/build.properties b/client/api/build.properties deleted file mode 100644 index 92a259c7..00000000 --- a/client/api/build.properties +++ /dev/null @@ -1,3 +0,0 @@ -FLEX_HOME_WINDOWS=C:/Program Files/Adobe/Adobe Flash Builder 4/sdks/3.4 -FLEX_HOME_LINUX=/opt/flex -PLAYER_VERSION=11.0 \ No newline at end of file diff --git a/client/api/build.xml b/client/api/build.xml deleted file mode 100644 index 245ede45..00000000 --- a/client/api/build.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/client/api/src/com/flashphoner/Logger.as b/client/api/src/com/flashphoner/Logger.as deleted file mode 100644 index fea6b72c..00000000 --- a/client/api/src/com/flashphoner/Logger.as +++ /dev/null @@ -1,161 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner -{ - - import com.flashphoner.api.data.PhoneConfig; - - import flash.system.Capabilities; - - public class Logger - { - [Bindable] - /** - * String which contain full logs. - **/ - public static var log:String = new String(); - - public static var SEVERITY:Object = new Object(); - - public static var SEVERITY_VALUE:int = 30; - - /** - * Default constructor - **/ - public static function init():void - { - SEVERITY["ERROR"]=10; - SEVERITY["WARN"]=20; - SEVERITY["INFO"]=30; - SEVERITY["DEBUG"]=40; - SEVERITY["TRACE"]=50; - SEVERITY_VALUE = SEVERITY[PhoneConfig.LOG_SEVERITY]; - trace("Init logger, SEVERITY: "+PhoneConfig.LOG_SEVERITY+" "+SEVERITY_VALUE); - } - - private static function getTime() : String - { - var dt : Date = new Date(); - var str : String = 'UTC ' + dt.getUTCMonth() + '.' + dt.getUTCDate() + ' ' + dt.getUTCHours() + ':' + dt.getUTCMinutes() + ':' + dt.getUTCSeconds() + '.' + dt.getUTCMilliseconds() + ': '; - return str; - } - - /** - * Add info message to log and output to trace - **/ - public static function info(str : String) : void - { - _log(str,"INFO"); - } - - /** - * Add debug message to log and output to trace - **/ - public static function debug(str : String) : void - { - _log(str,"DEBUG"); - } - - /** - * Add error message to log and output to trace - **/ - public static function error(str : String) : void - { - _log(str,"ERROR"); - } - - public static function warn(str : String) : void - { - _log(str,"WARN"); - - } - - public static function _trace(str : String) : void - { - _log(str,"TRACE"); - - } - - private static function _log(str:String,severity:String):void{ - if (SEVERITY[severity] <= SEVERITY_VALUE ){ - str = severity+': ' + getTime() + str + "\n"; - trace(str); - log += str + ''; - } - } - - public static function clear():void { - log = new String(); - } - - //merge two logs together based on time - public static function merge(logsJS:String):String { - //split logs to Arrays of Strings - var logsJSArray:Array = logsJS.split("\n"); - var logArray:Array = log.split("\n"); - - //create time pattern - var timePattern:RegExp = /[0-9]*:[0-9]*:[0-9]*\.[0-9]*/; - - //create new array and fill it with data - var resultingArray:Array = new Array(); - - var result:Array = new Array(); - var s:String; - - for each (s in logsJSArray) { - result = s.match(timePattern); - if (result != null) { - resultingArray.push([logTimeToInt(result[0]) , "[JS]\t" + s]); - } - } - - for each (s in logArray) { - result = s.match(timePattern); - if (result != null) { - resultingArray.push([logTimeToInt(result[0]), "[FLASH]\t" + s]); - } - } - - //sort array based on time - resultingArray.sortOn("0"); - - var resultingLogs:String = new String(); - var i:Array; - for each (i in resultingArray) { - resultingLogs += i[1] + "\n"; - } - - return resultingLogs; - } - - private static function logTimeToInt(s:String):int { - s = s.replace(/:/g, ""); - - var ms:String = s.substr(s.indexOf(".")); - var replaceStr:String = new String(""); - if(ms.length == 2) { - replaceStr = "00"; - } else if (ms.length == 3) { - replaceStr = "0"; - } - - s = s.replace(/\./, replaceStr); - var result:int = int(s); - return result; - } - - - - } -} diff --git a/client/api/src/com/flashphoner/api/Call.as b/client/api/src/com/flashphoner/api/Call.as deleted file mode 100644 index eddfd534..00000000 --- a/client/api/src/com/flashphoner/api/Call.as +++ /dev/null @@ -1,253 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - - import flash.events.TimerEvent; - import flash.utils.Timer; - - /** - * Class which contain data of call anf method for hangup,trasfer,hold. - **/ - [Bindable] - public class Call - { - - public static const STATE_RING:String = "RING"; - public static const STATE_HOLD:String = "HOLD"; - public static const STATE_TALK:String = "TALK"; - public static const STATE_FINISH:String = "FINISH"; - public static const STATE_BUSY:String = "BUSY"; - public static const STATE_SESSION_PROGRESS:String = "SESSION_PROGRESS"; - - - /** - * Video state of the call (sendrecv / recvonly etc.) - **/ - public var state_video:String; - - /** - * Identifier of call - **/ - public var id:String; - /** - * State of call (RING,HOLD,TALK,FINISH,BUSY,SESSION_PROGRESS) - **/ - public var state:String; - /** - * Flag on execute hold operation - * true - if user execute call.hold(true) - * false - if user execute call.hold(false) - **/ - public var iHolded:Boolean = false; - - /** - * Sip state of call - **/ - public var sip_state:String; - /** - * Not initiator of the call - **/ - public var callee:String; - /** - * Initiator of the call - **/ - public var caller:String; - /** - * Not initiators visible name of the call - **/ - public var visibleNameCallee:String; - /** - * Initiators visible name of the call - **/ - public var visibleNameCaller:String; - /** - * Player video format (CIF,QCIF) - **/ - public var playerVideoHeight:int; - - public var playerVideoWidth:int; - /** - * Streamer video format (CIF,QCIF) - **/ - public var streamerVideoHeight:int; - - public var streamerVideoWidth:int; - /** - * Time of call - **/ - public var timeOfCall:int = 0; - private var timer:Timer; - /** - * Another side logged user of call - **/ - public var anotherSideUser:String; - - /** - * Flag on incomming call - **/ - public var incoming:Boolean = false; - /** - * Flag on video call - **/ - public var isVideoCall:Boolean = false; - - public var isVideoSended:Boolean = false; - - private var callServerProxy:CallServerProxy; - - internal var flash_API:Flash_API; - - /** - * @param flash_API Api to be used for this call - **/ - public function Call(flash_API:Flash_API) - { - this.flash_API = flash_API; - callServerProxy = new CallServerProxy(this,flash_API.phoneServerProxy.nc); - } - /** - * Hangup this call - **/ - public function hangup():void{ - callServerProxy.unpublish(); - callServerProxy.hangup(); - SoundControl.stopRingSound(); - } - /** - * Change state of call (HOLD/TALK) - */ - public function setStatusHold(isHold:Boolean):void{ - if (state == Call.STATE_TALK || state == Call.STATE_HOLD){ - callServerProxy.hold(isHold); - } - } - - /** - * Transfer call to another user - * @param callee Target transfer call - **/ - public function transfer(callee:String):int{ - var modelLocator:ModelLocator = flash_API.modelLocator; - if (PhoneConfig.CHECK_VALIDATION_CALLEE){ - var reg:RegExp = /[a-zа-яё]/i; - if (callee != null && callee != ""){ - if ((callee.indexOf("sip:") == 0)){ - if (callee.indexOf("@") == -1 || callee.indexOf("@") == callee.length-1){ - return 1; - } - }else{ - if (callee.search(reg) != -1){ - if (callee.indexOf("@") != -1){ - return 1; - } - if (callee.indexOf(":") != -1){ - return 1; - } - callee = "sip:"+callee+"@"+modelLocator.domain+":"+modelLocator.port; - } - } - }else{ - return 1; - } - } - for each (var tempCall:Call in flash_API.calls){ - if (tempCall.state == Call.STATE_TALK && tempCall.id != id){ - tempCall.setStatusHold(true); - } - } - callServerProxy.transfer(callee); - SoundControl.stopRingSound(); - return 0; - } - - /** - * Answer on incoming call - * @param isVideoCall true - if answer with video (default - false). - **/ - public function answer(isVideoCall:Boolean = false):void{ - SoundControl.stopRingSound(); - for each (var tempCall:Call in flash_API.calls){ - if (tempCall.state == Call.STATE_TALK && tempCall.id != id){ - tempCall.setStatusHold(true); - } - } - callServerProxy.answer(isVideoCall); - } - /** - * Start/stop sending video to the server - * @param flag true - if start send video. - **/ - public function setSendVideo(flag:Boolean):void{ - callServerProxy.setSendVideo(flag); - } - - /** - * Send dtmf command to the sip provider - * @param dtmf DTMF command - **/ - public function sendDTMF(dtmf:String):void{ - callServerProxy.sendDtmf(dtmf); - } - - /** - * @private - * Publish video and audio streams - **/ - internal function publish():void{ - callServerProxy.publish(flash_API.modelLocator.login); - } - /** - * @private - * Unpublish video and audio streams - **/ - internal function unpublish():void{ - callServerProxy.unpublish(); - } - /** - * @private - * Start timer of call - **/ - internal function startTimer():void{ - if (timer!=null){ - timer.removeEventListener(TimerEvent.TIMER,timerHandler); - timer.stop(); - timer = null; - } - timeOfCall = 0; - timer = new Timer(999); - timer.addEventListener(TimerEvent.TIMER,timerHandler); - timer.start(); - } - - /** - * @private - * Stop timer of call - **/ - internal function stopTimer():void{ - timeOfCall = 0; - if (timer != null){ - timer.removeEventListener(TimerEvent.TIMER,timerHandler); - timer.stop(); - timer = null; - } - } - - private function timerHandler(timeEvent:TimerEvent):void{ - timeOfCall++; - } - - } -} diff --git a/client/api/src/com/flashphoner/api/CallCommand.as b/client/api/src/com/flashphoner/api/CallCommand.as deleted file mode 100644 index 3b5d2961..00000000 --- a/client/api/src/com/flashphoner/api/CallCommand.as +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - - import com.adobe.cairngorm.commands.ICommand; - import com.adobe.cairngorm.control.CairngormEvent; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.management.VideoControl; - - import flash.events.*; - import flash.utils.*; - - internal class CallCommand implements ICommand - { - private var hangupTimer:Timer; - - public function CallCommand() - { - } - - private function getStreamName(modelLocator:ModelLocator, call:Call) : String - { - return "INCOMING_"+modelLocator.login+"_"+call.id; - } - - public function execute( event : CairngormEvent ) : void - { - Logger.info("PhoneCommand.execute() event.type "+event.type); - - var call:Call = (event as CallEvent).call; - var flashAPI:Flash_API = call.flash_API; - var modelLocator:ModelLocator = flashAPI.modelLocator; - - if (event.type==CallEvent.TALK){ - Logger.info("MainEvent.TALK "+call.id); - SoundControl.stopRingSound(); - - call.startTimer(); - call.publish(); - flashAPI.phoneServerProxy.phoneSpeaker.play(getStreamName(modelLocator, call), true); - } - - if (event.type==CallEvent.HOLD){ - call.unpublish(); - } - - if (event.type == CallEvent.SESSION_PROGRESS){ - Logger.info("MainEvent.SESSION_PROGRESS"); - SoundControl.stopRingSound(); - flashAPI.phoneServerProxy.phoneSpeaker.play(getStreamName(modelLocator, call), true); - } - - if (event.type==CallEvent.IN){ - SoundControl.playRingSound(); - flashAPI.phoneServerProxy.phoneSpeaker.play(getStreamName(modelLocator, call), false); - } - - if (event.type ==CallEvent.OUT){ - SoundControl.playRingSound(); - flashAPI.phoneServerProxy.phoneSpeaker.play(getStreamName(modelLocator, call), false); - } - - if (event.type == CallEvent.BUSY){ - SoundControl.playBusySound(); - SoundControl.stopRingSound(); - } - if (event.type == CallEvent.FINISH){ - SoundControl.playFinishSound(); - SoundControl.stopRingSound(); - - call.stopTimer(); - call.unpublish(); - flashAPI.removeCall(call.id); - flashAPI.phoneServerProxy.phoneSpeaker.stop(call.id); - } - - } - } -} diff --git a/client/api/src/com/flashphoner/api/CallEvent.as b/client/api/src/com/flashphoner/api/CallEvent.as deleted file mode 100644 index da6fcda9..00000000 --- a/client/api/src/com/flashphoner/api/CallEvent.as +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.control.CairngormEvent; - - import flash.events.Event; - - /** - * Phone event - describe all phone events - * **/ - internal class CallEvent extends CairngormEvent - { - public static const IN:String = "IN"; - public static const OUT:String = "OUT"; - public static const TALK:String = "TALK"; - public static const HOLD:String = "HOLD"; - public static const BUSY:String = "BUSY"; - public static const FINISH:String = "FINISH"; - public static const SESSION_PROGRESS:String = "SESSION_PROGRESS"; - - public var call:Call; - - public function CallEvent(type:String,call:Call):void - { - super(type,bubbles,cancelable); - this.call = call; - } - - } -} diff --git a/client/api/src/com/flashphoner/api/CallServerProxy.as b/client/api/src/com/flashphoner/api/CallServerProxy.as deleted file mode 100644 index cb4d0e14..00000000 --- a/client/api/src/com/flashphoner/api/CallServerProxy.as +++ /dev/null @@ -1,149 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.flashphoner.Logger; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.management.VideoControl; - - import flash.events.AsyncErrorEvent; - import flash.events.NetStatusEvent; - import flash.media.Camera; - import flash.media.H264Profile; - import flash.media.H264VideoStreamSettings; - import flash.net.NetConnection; - import flash.net.NetStream; - import flash.net.Responder; - - internal class CallServerProxy - { - private var outStream:NetStream; - - private var nc:NetConnection; - private var flashCall:Call; - - private var sendVideo:Boolean = false; - - public function CallServerProxy(call:Call,nc:NetConnection) - { - this.nc = nc; - this.flashCall = call; - } - - public function sendDtmf(dtmf:String):void{ - Logger.info("CallServerProxy.sendDtmf() "+dtmf); - var dtmfObject:Object = new Object(); - dtmfObject.callId = flashCall.id; - dtmfObject.dtmf = dtmf; - nc.call("sendDtmf", null, dtmfObject); - } - - public function hangup():void{ - Logger.info("CallServerProxy.hangup() call.id: "+ flashCall.id); - nc.call("hangup", null, flashCall.id); - } - - public function transfer(callee:String):void{ - Logger.info("CallServerProxy.transfer() call.id: "+flashCall.id+";callee: "+callee); - var transferObject:Object = new Object(); - transferObject.callId = flashCall.id; - transferObject.callee = callee; - nc.call("transfer", null, transferObject); - } - - public function hold(isHold:Boolean):void{ - Logger.info("CallServerProxy.setStatusHold() call.id: "+flashCall.id+";isHold: "+isHold); - var holdObject:Object = new Object(); - holdObject.callId = flashCall.id; - holdObject.isHold = isHold; - nc.call("hold",null,holdObject); - } - - public function answer(isVideoCall:Boolean):void{ - Logger.info("CallServerProxy.answer() call.id: "+flashCall.id); - var answerObject:Object = new Object(); - answerObject.callId = flashCall.id; - answerObject.hasVideo = isVideoCall; - nc.call("answer",null,answerObject); - } - - public function publish(login:String):void{ - Logger.info("CallServerProxy.publish() login: "+login+";call.id: "+flashCall.id); - if (outStream == null){ - outStream = new NetStream(nc); - outStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler); - outStream.addEventListener(NetStatusEvent.NET_STATUS,onNetStatus); - outStream.attachAudio(flashCall.flash_API.soundControl.getMicrophone()); - outStream.audioReliable = PhoneConfig.AUDIO_RELIABLE; - outStream.videoReliable = PhoneConfig.VIDEO_RELIABLE; - - if (PhoneConfig.VIDEO_ENABLED && sendVideo){ - setVideoCompressionSettings(outStream); - } - /* outStream.publish(login+"_"+flashCall.id); - WSP-1703 - Removed "login_" from stream name. No need now. - */ - outStream.publish((flashCall.incoming ? "0":"1") + "_" + flashCall.id); - } - } - - private function setVideoCompressionSettings(outStream:NetStream):void{ - if (PhoneConfig.MAJOR_PLAYER_VERSION >= 11 && PhoneConfig.AVOID_FLV2H264_TRANSCODING){ - Logger.info("Player 11. Using h.264 compresstion settings...") - var settings:flash.media.H264VideoStreamSettings= new flash.media.H264VideoStreamSettings(); - settings.setProfileLevel(H264Profile.BASELINE, flash.media.H264Level.LEVEL_3); - outStream.videoStreamSettings = settings; - } - var cam:Camera = flashCall.flash_API.videoControl.getCam(); - outStream.attachCamera(cam); - Logger.info("attach video stream: "+cam.width+"x"+cam.height); - } - - public function unpublish():void{ - Logger.info("CallServerProxy.unpublish() call.id: "+flashCall.id); - if (outStream != null){ - outStream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler); - outStream.removeEventListener(NetStatusEvent.NET_STATUS,onNetStatus); - outStream.close(); - outStream=null; - } - } - public function setSendVideo(flag:Boolean):void{ - sendVideo = flag; - - if (outStream == null){ - return; - } - - if (PhoneConfig.VIDEO_ENABLED && sendVideo && flashCall != null){ - - if (flashCall.state_video != "sendrecv") { - nc.call("updateCallToVideo",null,flashCall.id); - } - - flashCall.isVideoSended = true; - setVideoCompressionSettings(outStream); - } - - if (!sendVideo){ - outStream.attachCamera(null); - } - } - - private function asyncErrorHandler(event: AsyncErrorEvent):void { - } - - private function onNetStatus(event : NetStatusEvent) : void{ - } - } -} diff --git a/client/api/src/com/flashphoner/api/Flash_API.as b/client/api/src/com/flashphoner/api/Flash_API.as deleted file mode 100644 index 52b32ecf..00000000 --- a/client/api/src/com/flashphoner/api/Flash_API.as +++ /dev/null @@ -1,709 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ - -package com.flashphoner.api -{ - import com.flashphoner.Logger; - import com.flashphoner.api.data.ErrorCodes; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.API; - import com.flashphoner.api.interfaces.APINotify; - import com.flashphoner.api.js.APINotifyJS; - import com.flashphoner.api.management.VideoControl; - - import flash.events.TimerEvent; - import flash.external.ExternalInterface; - import flash.media.Camera; - import flash.media.Microphone; - import flash.net.Responder; - import flash.net.SharedObject; - import flash.system.Security; - import flash.utils.Timer; - - import mx.collections.ArrayCollection; - - [Bindable] - public class Flash_API - { - private var registeredTimer:Timer; - /** - * @private - **/ - internal var phoneServerProxy:PhoneServerProxy; - /** - * List of calls - **/ - public var calls:ArrayCollection; - /** - * @private - * Notifier added by addNotify() - **/ - public static var apiNotifys:ArrayCollection; - /** - * Data about logged user - **/ - public var modelLocator:ModelLocator; - - /** - * management sounds and microphone - **/ - public var soundControl:SoundControl; - - /** - * Control of video - **/ - public var videoControl:VideoControl; - - /** - * - * Initialize parameters from 'flashphoner.xml' and another - **/ - public static function initLibrary():void{ - PhoneModel.getInstance(); - } - /** - * Default contructor. - * Initialize calls,modelLocato and initialize library - */ - public function Flash_API(apiNotify:APINotify){ - Security.allowDomain("*"); - Logger.init(); - apiNotifys = new ArrayCollection(); - addAPINotify(apiNotify); - PhoneModel.getInstance(); - ExternalInterface.addCallback("getParameters",getParameters); - ExternalInterface.addCallback("login",login); - ExternalInterface.addCallback("loginByToken",loginByToken); - ExternalInterface.addCallback("logoff",logoff); - ExternalInterface.addCallback("getInfoAboutMe",getInfoAboutMe); - ExternalInterface.addCallback("sendMessage",sendMessage); - ExternalInterface.addCallback("notificationResult",notificationResult); - ExternalInterface.addCallback("call",call); - ExternalInterface.addCallback("callByToken",callByToken); - ExternalInterface.addCallback("msrpCall",msrpCall); - ExternalInterface.addCallback("hangup",hangup); - ExternalInterface.addCallback("answer",answer); - ExternalInterface.addCallback("subscribe",subscribe); - ExternalInterface.addCallback("sendDTMF",sendDTMF); - ExternalInterface.addCallback("setStatusHold",setStatusHold); - ExternalInterface.addCallback("transfer",transfer); - ExternalInterface.addCallback("setSendVideo",setSendVideo); - ExternalInterface.addCallback("getMicVolume",getMicVolume); - ExternalInterface.addCallback("setMicVolume",setMicVolume); - ExternalInterface.addCallback("getVolume",getVolume); - ExternalInterface.addCallback("setVolume",setVolume); - ExternalInterface.addCallback("hasAccessToAudio",hasAccessToAudio); - ExternalInterface.addCallback("hasAccessToVideo",hasAccessToVideo); - ExternalInterface.addCallback("getMicropones",getMicropones); - ExternalInterface.addCallback("setMicrophone",setMicrophone); - ExternalInterface.addCallback("getCameras",getCameras); - ExternalInterface.addCallback("setCamera",setCamera); - ExternalInterface.addCallback("getCurrentCall",getCurrentCall); - ExternalInterface.addCallback("setCookie",setCookie); - ExternalInterface.addCallback("getCookie",getCookie); - ExternalInterface.addCallback("getVersion",getVersion); - ExternalInterface.addCallback("sendInfo",sendInfo); - ExternalInterface.addCallback("setSpeexQuality",setSpeexQuality); - ExternalInterface.addCallback("playSound",playSound); - ExternalInterface.addCallback("stopSound", stopSound); - ExternalInterface.addCallback("pushLogs", pushLogs); - ExternalInterface.addCallback("sendXcapRequest", sendXcapRequest); - ExternalInterface.addCallback("openSettingsPanel",openSettingsPanel); - ExternalInterface.addCallback("submitBugReport",submitBugReport); - ExternalInterface.addCallback("setLTState",setLTState); - calls = new ArrayCollection(); - modelLocator = new ModelLocator(); - phoneServerProxy = new PhoneServerProxy(new Responder(result),this); - - } - - public function initMedia():void{ - Logger.info("Init media..."); - soundControl = new SoundControl(this); - videoControl = new VideoControl(); - } - - /** - * Hangup call by id - * @param callId Identifier of call - **/ - public function hangup(callId:String):void{ - var call:Call = getCallById(callId); - if (call != null){ - call.hangup(); - } - } - - /** - * Answer call by id - * @param callId Identifier of call - * @param isVideoCall video call?(true/false) - **/ - public function answer(callId:String, isVideoCall:Boolean = false):void{ - var call:Call = getCallById(callId); - if (call != null){ - call.answer(isVideoCall); - } - } - - /** - * Send dtmf to voip server - * @param callId Identifier of call - * @param dtmf command for dtmf - **/ - public function sendDTMF(callId:String,dtmf:String):void{ - var call:Call = getCallById(callId); - if (call != null){ - call.sendDTMF(dtmf); - } - } - - /** - * Hold/Unhold call - * @param callId Identifier of call - * @param isHold true, if set state hold - **/ - public function setStatusHold(callId:String,isHold:Boolean = true):void{ - Logger.info("setStatusHold; callId - " + callId + "; isHold - " + isHold); - var call:Call = getCallById(callId); - if (call != null){ - call.setStatusHold(isHold); - } - } - - /** - * Transfer call - * @param callId Identifier of call - * @param target target for transfer call - **/ - public function transfer(callId:String,target:String):void{ - var call:Call = getCallById(callId); - if (call != null){ - call.transfer(target); - } - } - - /** - * Start/stop video stream - * @param isSend true, if start(true/false) - **/ - public function setSendVideo(callId:String, isSend:Boolean):void{ - var call:Call = getCallById(callId); - if (call != null){ - call.setSendVideo(isSend); - } - } - - /** - * Get current call in TALK-state - **/ - public function getCurrentCall():Call{ - for each(var obj:* in calls){ - if (obj.state == Call.STATE_TALK){ - return Call(obj); - } - } - return null; - } - - /** - * Get call by indetifier - * @param callId Identifier of call - **/ - public function getCallById(callId:String):Call{ - for each(var obj:* in calls){ - if (obj.id == callId){ - return Call(obj); - } - } - return null; - } - - /** - * Get call by index - * @param index Index in calls collection - **/ - public function getCallByIndex(index:Number):Call{ - var obj:* = calls.getItemAt(index); - if (obj != null){ - return Call(obj); - } - return null; - } - - /** - * Get index by call identifier - * @param callId Identifier of call - * @return -1 - if call not found - **/ - public function getIndexByCallId(callId:String):Number{ - for (var index:* in calls){ - var obj:* = calls.getItemAt(index); - if (obj.id == callId){ - return index; - } - } - return -1; - } - - /** - * @private - * Add call to calls collection - **/ - internal function addCall(call:Call):void{ - for (var index:* in calls){ - var obj:* = calls.getItemAt(index); - if (obj.id == call.id){ - return; - } - } - calls.addItem(call); - for each (var apiNotify:APINotify in apiNotifys){ - apiNotify.notifyAddCall(call); - } - } - /** - * @private - * Remove call from calls collection - * @param callId Identifier of call - **/ - internal function removeCall(callId:String):void{ - var hasTalkState:Boolean = false; - for (var index:* in calls){ - var obj:* = calls.getItemAt(index); - if (obj.id == callId){ - for each (var apiNotify:APINotify in apiNotifys){ - apiNotify.notifyRemoveCall(Call(obj)); - } - calls.removeItemAt(index); - } else if (obj.state == Call.STATE_TALK){ - hasTalkState = true; - } - } - if (!hasTalkState){ - for each (var call:Call in calls){ - if (call.state == Call.STATE_HOLD){ - if (call.iHolded){ - call.setStatusHold(false); - } - } - - } - } - } - - /** - * Get controller of speaker - **/ - public function getPhoneSpeaker():PhoneSpeaker{ - return this.phoneServerProxy.phoneSpeaker; - } - - /** - * Add notifier to api - * @param apiNotify Object will be implemented APINotify - **/ - public function addAPINotify(apiNotify:APINotify):void{ - Flash_API.apiNotifys.addItem(apiNotify); - } - /** - * Get parameters from file 'flashphoner.xml' - **/ - public function getParameters():Object{ - var object:Object = PhoneModel.getInstance().parameters; - if (object == null){ - return ErrorCodes.PARAMETERS_IS_NOT_INITIALIZED; - }else{ - return PhoneModel.getInstance().parameters; - } - } - - /** - * Get full version of server - **/ - public function getVersion():String{ - return PhoneConfig.getFullVersion(); - } - - /** - * Authentication on sip provider server on "flashphoner" mode - * @param username sip format username (example: sip:...) - * @param password Password for user - **/ - public function login(loginObject:Object, WCSUrl:String):int{ - videoControl.init(); - return phoneServerProxy.login(loginObject, WCSUrl); - } - - /** - * Authentication on sip provider server on "flashphoner" mode with token - * @param token Token for auth server - * @param password Password for user - **/ - public function loginByToken(WCSUrl:String, token:String = null, pageUrl:String = null):void{ - - /** - * pageUrl need here by that reason = WSP-1855 "Problem with pageUrl in Firefox" - * if client broswer is Firefox, default pageUrl not works, and we send from js special pageUrl - */ - Logger.info("loginByToken: " + token + ", pageUrl: " + pageUrl); - var obj:Object = {}; - obj.token = token; - obj.pageUrl = pageUrl; - - videoControl.init(); - phoneServerProxy.login(obj, WCSUrl); - } - - /** - * Create new call - * @param callee login of user - target call - * @param visibleName name of logged user wich target user see - * @param isVideoCall video call?(true/false) - **/ - public function call(callObject:Object):int{ - if (PhoneConfig.CHECK_VALIDATION_CALLEE){ - var reg:RegExp = /[a-zа-яё]/i; - var callee = callObject.callee; - if (callee != null && callee != ""){ - if ((callee.indexOf("sip:") == 0)){ - if (callee.indexOf("@") == -1 || callee.indexOf("@") == callee.length-1){ - return 1; - } - }else if (callee.indexOf("tel:") == 0){ - if (callee.substring(4).search(reg) != -1){ - return 1; - } - }else{ - if (callee.search(reg) != -1){ - if (callee.indexOf("@") != -1){ - return 1; - } - if (callee.indexOf(":") != -1){ - return 1; - } - callObject.callee = "sip:"+callee+"@"+modelLocator.domain+":"+modelLocator.port; - } - } - }else{ - return 1; - } - } - if (callObject.visibleName != null){ - callObject.visibleName.replace("\"",""); - callObject.visibleName.replace("'",""); - } - for each (var tempCall:Call in calls){ - if (tempCall.state == Call.STATE_TALK){ - tempCall.setStatusHold(true); - } - } - phoneServerProxy.call(callObject); - return 0; - } - - /** - * Create new call by URL - * @param isVideoCall video call?(true/false) - **/ - public function callByToken(callObject:Object):int{ - phoneServerProxy.callByToken(callObject); - return 0; - } - - /** - * Create new msrp call - * @param call object - **/ - public function msrpCall(callObject:Object):int{ - phoneServerProxy.msrpCall(callObject); - return 0; - } - - /** - * Get information about logged user - **/ - public function getInfoAboutMe():ModelLocator{ - return modelLocator; - } - - /** - * Get state of flash_api - * @return boolean of initialized state - **/ - public function isInitialized():Boolean{ - return PhoneModel.getInstance().initialized; - } - - /** - * Get volume of current microphone - * @return volume interval 1-100 - **/ - public function getMicVolume():int{ - var mic:Microphone = soundControl.getMicrophone(); - if (mic == null){ - return 0; - }else{ - return mic.gain; - } - - } - - /** - * Set volume for current microphone - * @param volume interval 1-100 - **/ - public function setMicVolume(volume:int):void{ - var mic:Microphone = soundControl.getMicrophone(); - if (mic != null){ - mic.gain = volume; - } - } - - /** - * Get volume of speakers - * @return volume interval 1-100 - **/ - public function getVolume():int{ - return phoneServerProxy.phoneSpeaker.getVolume(); - } - - /** - * Set volume for speakers - * @param volume interval 1-100 - **/ - public function setVolume(volume:int):void{ - phoneServerProxy.phoneSpeaker.setVolume(volume); - } - - /** - * Get list of microphones - **/ - public function getMicropones():Array{ - return Microphone.names; - } - - /** - * Set current microphone - * @param name name of microphone - **/ - public function setMicrophone(name:String):void{ - var i:int = 0; - for each (var nameMic:String in Microphone.names){ - if (nameMic == name){ - soundControl.changeMicrophone(i,false); - return; - } - i++; - } - } - - /** - * Check access to the devices (mic,camera) - **/ - public function hasAccessToAudio():Boolean{ - return soundControl.isMuted() == -1; - } - - /** - * Check access to the devices (mic,camera) - **/ - public function hasAccessToVideo():Boolean{ - return videoControl.isMuted() == -1; - } - - - /** - * Get list of cameras - **/ - public function getCameras():Array{ - return Camera.names; - } - - /** - * Set current camera - * @param name name of camera - **/ - public function setCamera(name:String):void{ - videoControl.changeCamera(Camera.getCamera(name)); - } - - /** - * Log off from the server and close connection - **/ - public function logoff():void{ - phoneServerProxy.disconnect(); - } - - /** - * Get cookie from flash - * @param key Key of the parameter - **/ - public function getCookie(key:String):String{ - var localSharedObject:SharedObject = SharedObject.getLocal("Flashphoner"); - if (localSharedObject!=null){ - return localSharedObject.data[key]; - } - return null; - } - - /** - * Set cookie to flash - * @param key Key of the parameter - * @param value Value of the parameter - **/ - public function setCookie(key:String,value:String):void{ - var localSharedObject:SharedObject = SharedObject.getLocal("Flashphoner"); - if (localSharedObject!=null){ - localSharedObject.setProperty(key,value); - } - } - - /** - * @private - **/ - internal function startRegisterTimer():void{ - registeredTimer.start(); - } - - - /** - * @private - * Start timer for REGISTER_EXPIRE error - **/ - internal function upRegisteredTimer():void{ - if (registeredTimer!=null){ - registeredTimer.stop(); - } else { - registeredTimer = new Timer(15000); - registeredTimer.addEventListener(TimerEvent.TIMER,registeredExpire); - } - } - - /** - * @private - * Stop timer for REGISTER_EXPIRE error - **/ - internal function dropRegisteredTimer():void{ - if (registeredTimer!=null){ - registeredTimer.stop(); - registeredTimer.removeEventListener(TimerEvent.TIMER,registeredExpire); - registeredTimer=null; - } - } - - /** - * Handler on registerTimer - **/ - private function registeredExpire(event:TimerEvent):void{ - for each (var apiNotify:APINotify in apiNotifys){ - apiNotify.notifyError(ErrorCodes.REGISTER_EXPIRE); - } - dropRegisteredTimer(); - } - /** - * Impementation for Responder - **/ - private function result(_call : Object) : void - { - var call:Call = new Call(this); - call.id = _call.id; - call.state = _call.state; - call.incoming=false; - call.callee = _call.callee; - call.anotherSideUser = _call.callee; - addCall(call); - } - - /** - * Send instance message to the user - * @param to target of the message - * @param body content of the message - * @param contentType type of content - **/ - public function sendMessage(msg:Object):void{ - this.phoneServerProxy.sendInstantMessage(msg); - } - - /** - * Send instance message to the user - * @param instantMessage - **/ - public function sendInstantMessage(instantMessage:InstantMessage):void{ - this.phoneServerProxy.sendInstantMessage(instantMessage); - } - - public function notificationResult(notificationResult:Object):void{ - Logger.info("notificationResult "+notificationResult); - this.phoneServerProxy.notificationResult(notificationResult); - } - - public function sendInfo(infoObj:Object):void { - this.phoneServerProxy.sendInfo(infoObj); - } - - public function setSpeexQuality(quality:int):void{ - soundControl.setSpeexQuality(quality); - } - - /** - * Added for compatibility with WebRTC implementation - **/ - public function playSound(sound:String):void{ - Logger.info("Received request to play sound " + sound); - } - - public function stopSound(sound:String):void{ - Logger.info("Received request to stop sound " + sound); - } - - public function pushLogs(logs:String):Boolean { - //check if push_log enabled - if (PhoneConfig.PUSH_LOG) { - var pushResult:Boolean = phoneServerProxy.pushLogs(logs); - return pushResult; - } else { - return false; - } - } - - - public function subscribe(subscribeObj:Object):void{ - this.phoneServerProxy.subscribe(subscribeObj); - } - - public function sendXcapRequest(xcapUrl:String):void{ - this.phoneServerProxy.sendXcapRequest(xcapUrl); - } - - public function openSettingsPanel():void{ - Security.showSettings(); - } - - public function submitBugReport(reportObj:Object):Boolean { - phoneServerProxy.submitBugReport(reportObj); - return true; - } - - public function pong():void { - phoneServerProxy.pong(); - } - - public function setLTState(state:String):void{ - var obj:Object = new Object(); - obj.state = state; - this.phoneServerProxy.setLTState(obj); - } - } -} diff --git a/client/api/src/com/flashphoner/api/InstantMessage.as b/client/api/src/com/flashphoner/api/InstantMessage.as deleted file mode 100644 index 0f355ab6..00000000 --- a/client/api/src/com/flashphoner/api/InstantMessage.as +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - public class InstantMessage - { - - public function InstantMessage() - { - } - - public var from:String; - - - /** - * Target of the message - **/ - public var to:String; - - /** - * Content of the message - **/ - public var body:String; - - /** - * Type of content - **/ - public var contentType:String; - - public var recipients:String; - - public var deliveryNotification:String; - } -} diff --git a/client/api/src/com/flashphoner/api/MainCommand.as b/client/api/src/com/flashphoner/api/MainCommand.as deleted file mode 100644 index 7db734d9..00000000 --- a/client/api/src/com/flashphoner/api/MainCommand.as +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - - import com.adobe.cairngorm.commands.ICommand; - import com.adobe.cairngorm.control.CairngormEvent; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - - import flash.events.*; - import flash.utils.*; - - import mx.collections.ArrayCollection; - - internal class MainCommand implements ICommand - { - private var hangupTimer:Timer; - - public function MainCommand() - { - } - - public function execute( event : CairngormEvent ) : void - { - Logger.info("PhoneCommand.execute() event.type "+event.type); - - var flashAPI:Flash_API = (event as MainEvent).flashAPI; - var modelLocator:ModelLocator = flashAPI.modelLocator; - - if (event.type == MainEvent.CONNECTED){ - if (!PhoneConfig.REGISTER_REQUIRED){ - modelLocator.logged = true; - SoundControl.playRegisterSound(); - } - } - if (event.type == MainEvent.REGISTERED){ - modelLocator.logged = true; - flashAPI.dropRegisteredTimer(); - SoundControl.playRegisterSound(); - } - - if (event.type == MainEvent.DISCONNECT){ - SoundControl.stopRingSound(); - modelLocator.logged = false; - modelLocator.login = null; - modelLocator.pwd = null; - flashAPI.calls = new ArrayCollection(); - } - - if (event.type == MainEvent.AUDIO_CODEC_CHANGED_EVENT){ - var codec:Object = (event as MainEvent).obj; - flashAPI.soundControl.changeAudioCodec(codec); - } - - if (event.type == MainEvent.VIDEO_FORMAT_CHANGED){ - var mediaFormat:Object = (event as MainEvent).obj; - flashAPI.videoControl.changeFormat(mediaFormat.streamerVideoWidth,mediaFormat.streamerVideoHeight); - //flashAPI.phoneServerProxy.phoneSpeaker.changeFormat(call.playerVideoWidth,call.playerVideoHeight); - } - - } - } -} diff --git a/client/api/src/com/flashphoner/api/MainEvent.as b/client/api/src/com/flashphoner/api/MainEvent.as deleted file mode 100644 index 2d82f8f4..00000000 --- a/client/api/src/com/flashphoner/api/MainEvent.as +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.control.CairngormEvent; - - import flash.events.Event; - - /** - * Phone event - describe all phone events - * **/ - internal class MainEvent extends CairngormEvent - { - public static const CONNECTED:String = "CONNECTED"; - public static const REGISTERED:String = "REGISTERED"; - public static const DISCONNECT:String = "DISCONNECT"; - public static const MESSAGE_ACCEPTED:String = "MESSAGE_ACCEPTED"; - public static const VIDEO_FORMAT_CHANGED:String = "VIDEO_FORMAT_CHANGED"; - public static const AUDIO_CODEC_CHANGED_EVENT:String = "AUDIO_CODEC_CHANGED_EVENT"; - - public var flashAPI:Flash_API; - public var obj:Object; - - public function MainEvent(type:String, flashAPI:Flash_API):void - { - super(type); - this.flashAPI = flashAPI; - } - - } -} diff --git a/client/api/src/com/flashphoner/api/MessageCommand.as b/client/api/src/com/flashphoner/api/MessageCommand.as deleted file mode 100644 index 6ae795ec..00000000 --- a/client/api/src/com/flashphoner/api/MessageCommand.as +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - - import com.adobe.cairngorm.commands.ICommand; - import com.adobe.cairngorm.control.CairngormEvent; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - - import flash.events.*; - import flash.utils.*; - - import mx.collections.ArrayCollection; - - internal class MessageCommand implements ICommand - { - - public function MessageCommand() - { - } - - public function execute( event : CairngormEvent ) : void - { - Logger.info("MessageCommand.execute() event.type "+event.type); - - var messageEvent:MessageEvent = event as MessageEvent; - var flashAPI:Flash_API = messageEvent.flashAPI; - if (event.type == MessageEvent.MESSAGE_EVENT){ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyMessage(messageEvent.messageObj,messageEvent.notificationResult,messageEvent.sipObject); - } - } - - - } - } -} diff --git a/client/api/src/com/flashphoner/api/MessageEvent.as b/client/api/src/com/flashphoner/api/MessageEvent.as deleted file mode 100644 index 7333e949..00000000 --- a/client/api/src/com/flashphoner/api/MessageEvent.as +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.control.CairngormEvent; - - import flash.events.Event; - - /** - * Message event - describe all phone events - * **/ - internal class MessageEvent extends CairngormEvent - { - public static const MESSAGE_EVENT:String = "MESSAGE_EVENT"; - - public var flashAPI:Flash_API; - public var messageObj:Object; - public var notificationResult:Object; - public var sipObject:Object; - - public function MessageEvent(type:String,messageObj:Object, flashAPI:Flash_API ):void - { - super(type,bubbles,cancelable); - this.messageObj = messageObj; - this.flashAPI = flashAPI; - } - - } -} diff --git a/client/api/src/com/flashphoner/api/PhoneCallback.as b/client/api/src/com/flashphoner/api/PhoneCallback.as deleted file mode 100644 index 5fb2b3ec..00000000 --- a/client/api/src/com/flashphoner/api/PhoneCallback.as +++ /dev/null @@ -1,251 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - - import com.adobe.cairngorm.control.CairngormEventDispatcher; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ErrorCodes; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - - import flash.external.ExternalInterface; - import flash.net.NetConnection; - import flash.net.NetStream; - - public class PhoneCallback - { - private var flash_API:Flash_API; - public function PhoneCallback(flashAPI:Flash_API) - { - this.flash_API = flashAPI; - } - - public function ping():void{ - this.flash_API.pong(); - } - - public function notifyBalance(balance:Number,_sipObject:Object):void{ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyBalance(balance,_sipObject); - } - } - - public function notifyBugReport(filename:String):void{ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyBugReport(filename); - } - } - - public function getVersion(version:String):void{ - PhoneConfig.VERSION_OF_SERVER = version; - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyVersion(PhoneConfig.getFullVersion()); - } - } - - public function getUserData(resObj:Object):void{ - var modelLocator:ModelLocator = flash_API.modelLocator; - modelLocator.login = resObj.login; - modelLocator.pwd = resObj.password; - modelLocator.outboundProxy = resObj.outboundProxy; - modelLocator.domain = resObj.domain; - modelLocator.port = resObj.port; - - PhoneConfig.REGISTER_REQUIRED = resObj.regRequired; - ExternalInterface.call("notifyRegisterRequired",PhoneConfig.REGISTER_REQUIRED); - if (PhoneConfig.REGISTER_REQUIRED){ - flash_API.upRegisteredTimer(); - flash_API.startRegisterTimer(); - } - } - - public function fail(errorCode:String,_sipObject:Object):void{ - Logger.info("PhoneCallback.fail() "+errorCode); - if (errorCode == ErrorCodes.AUTHENTICATION_FAIL || errorCode == ErrorCodes.SIP_PORTS_BUSY){ - flash_API.dropRegisteredTimer(); - } - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyError(errorCode,_sipObject); - } - } - - public function close():void{ - } - - public function registered(_sipObject:Object):void{ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyRegistered(_sipObject); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new MainEvent(MainEvent.REGISTERED,flash_API)); - } - - public function ring(_call:Object,_sipObject:Object):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notify(call,_sipObject); - } - if (!call.incoming){ - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.OUT,call)); - } else { - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.IN,call)); - } - } - - public function sessionProgress(_call:Object,_sipObject:Object):void{ - var call:Call = process(_call); - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.SESSION_PROGRESS,call)); - } - - public function talk(_call:Object,_sipObject:Object):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notify(call,_sipObject); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.TALK,call)); - } - - public function hold(_call:Object, _sipObject:Object):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notify(call,_sipObject); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.HOLD,call)); - } - - // Notify about CIF 352x288 or QCIF 176x144 video format - public function notifyVideoFormat(videoFormat:Object):void{ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyVideoFormat(videoFormat); - } - var event:MainEvent = new MainEvent(MainEvent.VIDEO_FORMAT_CHANGED, flash_API); - event.obj = videoFormat; - CairngormEventDispatcher.getInstance().dispatchEvent(event); - } - - public function onVideoPlay(_call:Object, play:Boolean):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyOpenVideoView(play); - } - } - - public function callbackHold(callId:String, isHold:Boolean):void{ - var call:Call = flash_API.getCallById(callId); - call.iHolded = isHold; - if (!isHold){ - for each (var tempCall:Call in flash_API.calls){ - if (tempCall.state == Call.STATE_TALK && tempCall.id != call.id){ - tempCall.setStatusHold(true); - } - } - } - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyCallbackHold(call,isHold); - } - } - - public function busy(_call:Object,_sipObject:Object):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notify(call,_sipObject); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.BUSY,call)); - } - - public function finish(_call:Object,_sipObject:Object):void{ - var call:Call = process(_call); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notify(call,_sipObject); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new CallEvent(CallEvent.FINISH,call)); - } - - public function process(_call:Object):Call{ - Logger.info("PhoneCallback.process() id="+_call.id+" state="+_call.state+" callee="+_call.callee); - var call:Call = flash_API.getCallById(_call.id); - if (call==null){ - call = new Call(flash_API); - call.id = _call.id; - } - - call.incoming = _call.incoming; - call.isVideoCall = _call.isVideoCall; - call.callee = _call.callee; - call.caller = _call.caller; - if (call.incoming){ - call.anotherSideUser = _call.caller; - }else{ - call.anotherSideUser = _call.callee; - } - call.visibleNameCallee = _call.visibleNameCallee; - if (call.visibleNameCallee != null){ - call.visibleNameCallee = call.visibleNameCallee.replace("<",""); - call.visibleNameCallee = call.visibleNameCallee.replace(">",""); - } - call.visibleNameCaller = _call.visibleNameCaller; - if (call.visibleNameCaller != null){ - call.visibleNameCaller = call.visibleNameCaller.replace("<",""); - call.visibleNameCaller = call.visibleNameCaller.replace(">",""); - } - call.state = _call.state; - call.state_video = _call.state_video; - call.sip_state = _call.sip_state; - call.playerVideoHeight = _call.playerVideoHeight; - call.playerVideoWidth = _call.playerVideoWidth; - call.streamerVideoWidth = _call.streamerVideoWidth; - call.streamerVideoHeight = _call.streamerVideoHeight; - - flash_API.addCall(call); - Logger.info("PhoneCallback.process() complete id="+call.id+" state="+call.state+" callee="+call.callee); - return call; - } - - public function notifyMessage(messageObj:Object, notificationResult:Object, sipObject:Object):void { - Logger.info("Message has been accepted by other participant"); - var messageEvent:MessageEvent = new MessageEvent(MessageEvent.MESSAGE_EVENT,messageObj,flash_API); - messageEvent.notificationResult = notificationResult; - messageEvent.sipObject = sipObject; - CairngormEventDispatcher.getInstance().dispatchEvent(messageEvent); - } - - public function notifyAudioCodec(codec:Object):void { - Logger.info("notifyAudioCodec: "+codec); - var event:MainEvent = new MainEvent(MainEvent.AUDIO_CODEC_CHANGED_EVENT,flash_API); - event.obj = codec; - CairngormEventDispatcher.getInstance().dispatchEvent(event); - } - - public function notifyOptions(sipObj:Object):int { - Logger.info("notifyOptions "+sipObj); - return 200; - } - - public function notifySubscription(subscribtionObj:Object, sipObj:Object):void { - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifySubscription(subscribtionObj,sipObj); - } - } - - public function notifyXcapResponse(xcapResponse:String):void{ - Logger.info("notifyXcapResponse:\n"+xcapResponse); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyXcapResponse(xcapResponse); - } - } - - - - } -} diff --git a/client/api/src/com/flashphoner/api/PhoneController.as b/client/api/src/com/flashphoner/api/PhoneController.as deleted file mode 100644 index f43b899a..00000000 --- a/client/api/src/com/flashphoner/api/PhoneController.as +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.control.FrontController; - - /** - * Dispatcher for all application events - * **/ - internal class PhoneController extends FrontController - { - private static var UUID : String = "33de0550-44d6-4550-b133-43344716776a"; - - public function PhoneController() - { - init(); - } - - private function init(): void - { - addCommand(CallEvent.TALK , CallCommand ); - addCommand(CallEvent.HOLD , CallCommand ); - addCommand(CallEvent.OUT , CallCommand); - addCommand(CallEvent.IN , CallCommand); - addCommand(CallEvent.BUSY, CallCommand); - addCommand(CallEvent.FINISH,CallCommand); - addCommand(CallEvent.SESSION_PROGRESS,CallCommand); - - addCommand(MainEvent.CONNECTED,MainCommand); - addCommand(MainEvent.REGISTERED,MainCommand); - addCommand(MainEvent.DISCONNECT,MainCommand); - addCommand(MainEvent.AUDIO_CODEC_CHANGED_EVENT,MainCommand); - addCommand(MainEvent.VIDEO_FORMAT_CHANGED,MainCommand); - - addCommand(MessageEvent.MESSAGE_EVENT,MessageCommand); - - - } - } -} diff --git a/client/api/src/com/flashphoner/api/PhoneModel.as b/client/api/src/com/flashphoner/api/PhoneModel.as deleted file mode 100644 index d11f8608..00000000 --- a/client/api/src/com/flashphoner/api/PhoneModel.as +++ /dev/null @@ -1,265 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.model.IModelLocator; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ErrorCodes; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - import com.flashphoner.api.js.APINotifyJS; - - import flash.display.DisplayObjectContainer; - import flash.events.*; - import flash.external.ExternalInterface; - import flash.media.*; - import flash.net.*; - import flash.system.Capabilities; - import flash.utils.Timer; - - import mx.collections.ArrayCollection; - import mx.core.Application; - - /** - * Model object - * **/ - [Bindable] - public class PhoneModel implements IModelLocator - { - private static var phoneModel:PhoneModel; - - public var initialized:Boolean = false; - - private var xml:XML; - - public var app : DisplayObjectContainer; - private var phoneController:PhoneController; - public var parameters:Object = null; - - private static var initTimer:Timer; - - public static function getInstance():PhoneModel { - if (phoneModel == null){ - phoneModel = new PhoneModel(); - } - return phoneModel; - } - - - - public function PhoneModel() - { - super(); - startInitTimer(); - init(); - phoneController = new PhoneController(); - - } - - - private function init(event:TimerEvent = null):void{ - if (Application.application == null || Application.application.parameters == null){ - return; - }else{ - dropInitTimer(); - } - var loader:URLLoader = new URLLoader(); - var qwe:Object = Application.application.parameters; - var config:String = "flashphoner.xml"; - try{ - if (Application.application.parameters != null && Application.application.parameters.config!=null){ - config = Application.application.parameters.config; - } - } catch (e:Error){ - config = "flashphoner.xml"; - } - - var request:URLRequest = new URLRequest(config); - loader.load(request); - loader.addEventListener(Event.COMPLETE, onComplete); - loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,seurityErrorHandler); - loader.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler); - - setFlashPlayerMajorVersion(); - - } - - private function setFlashPlayerMajorVersion():void { - Logger.info("setFlashPlayerMajorVersion"); - var flashPlayerVersion:String = Capabilities.version; - var osArray:Array = flashPlayerVersion.split(' '); - var osType:String = osArray[0]; - var versionArray:Array = osArray[1].split(','); - PhoneConfig.MAJOR_PLAYER_VERSION = parseInt(versionArray[0]); - Logger.info("majorVersion "+PhoneConfig.MAJOR_PLAYER_VERSION); - } - - private function seurityErrorHandler(event:SecurityErrorEvent):void{ - throw new Error(event.toString()); - } - - private function ioErrorHandler(event:IOErrorEvent):void{ - throw new Error(event.toString()); - } - - private function onComplete(event:Event):void - { - var loader:URLLoader = event.target as URLLoader; - if (loader != null) - { - xml = new XML(loader.data); - var count:Number = xml.children().length(); - parameters = new Object(); - for (var i:Number = 0; i < count; i++) - { - var node:String = xml.children()[i].localName().toString(); - parameters[node] = String(xml[node]); - } - - var wcs_server:String = xml.wcs_server; - if (wcs_server!=null && wcs_server.length!=0){ - PhoneConfig.WCS_SERVER = wcs_server; - } - Logger.info("WCS_SERVER: "+PhoneConfig.WCS_SERVER); - - var rtmfp_port:String = xml.rtmfp_port; - if (rtmfp_port!=null && rtmfp_port.length!=0){ - PhoneConfig.RTMFP_PORT = int(rtmfp_port); - } - Logger.info("RTMFP_PORT: "+PhoneConfig.RTMFP_PORT); - - var use_enhanced_mic:String = xml.use_enhanced_mic; - - if (use_enhanced_mic!=null && use_enhanced_mic.length!=0){ - PhoneConfig.USE_ENHANCED_MIC = (use_enhanced_mic == "true"); - } - Logger.info("USE_ENHANCED_MIC: "+PhoneConfig.USE_ENHANCED_MIC); - - var forceEnhancedMic:String = xml.force_enhanced_mic; - if (forceEnhancedMic!=null && forceEnhancedMic.length!=0){ - PhoneConfig.FORCE_ENHANCED_MIC= (forceEnhancedMic=="true"); - } - Logger.info("FORCE_ENHANCED_MIC: "+PhoneConfig.FORCE_ENHANCED_MIC); - - var regRequired:String = xml.register_required; - PhoneConfig.REGISTER_REQUIRED = (regRequired == "true"); - - if (xml.video_width != null && xml.video_width.toString() != ""){ - PhoneConfig.VIDEO_WIDTH = int(xml.video_width); - } - if (xml.video_height != null && xml.video_height.toString() != ""){ - PhoneConfig.VIDEO_HEIGHT = int(xml.video_height); - } - - if (xml.keep_alive == "true"){ - PhoneConfig.KEEP_ALIVE=true; - } - Logger.info("KEEP_ALIVE: "+PhoneConfig.KEEP_ALIVE); - - if (xml.keep_alive_interval !=null && xml.keep_alive_interval.toString() !=""){ - PhoneConfig.KEEP_ALIVE_INTERVAL = int(xml.keep_alive_interval); - } - Logger.info("KEEP_ALIVE_INTERVAL: "+PhoneConfig.KEEP_ALIVE_INTERVAL); - - if (xml.keep_alive_timeout !=null && xml.keep_alive_timeout.toString() !=""){ - PhoneConfig.KEEP_ALIVE_TIMEOUT = int(xml.keep_alive_timeout); - } - Logger.info("KEEP_ALIVE_TIMEOUT: "+PhoneConfig.KEEP_ALIVE_TIMEOUT); - - if (xml.push_log != null && xml.push_log.toString() != ""){ - PhoneConfig.PUSH_LOG = (xml.push_log == "true"); - } - Logger.info("PUSH_LOG: "+PhoneConfig.PUSH_LOG); - - if (xml.audio_codec != null && xml.audio_codec.toString() != ""){ - PhoneConfig.AUDIO_CODEC = xml.audio_codec; - } - Logger.info("AUDIO_CODEC: "+PhoneConfig.AUDIO_CODEC); - - if (xml.g711_frames_per_packet != null && xml.g711_frames_per_packet.toString() != ""){ - PhoneConfig.G711_FRAMES_PER_PACKET = xml.g711_frames_per_packet; - } - Logger.info("G711_FRAMES_PER_PACKET: "+PhoneConfig.G711_FRAMES_PER_PACKET); - - if (xml.avoid_flv2h264_transcoding != null && xml.avoid_flv2h264_transcoding.toString() != ""){ - PhoneConfig.AVOID_FLV2H264_TRANSCODING = (xml.avoid_flv2h264_transcoding == "true"); - } - Logger.info("AVOID_H264_TRANSCODING: "+PhoneConfig.AVOID_FLV2H264_TRANSCODING); - - if (xml.audio_reliable != null && xml.audio_reliable.toString() != ""){ - PhoneConfig.AUDIO_RELIABLE = (xml.audio_reliable == "true"); - } - Logger.info("AUDIO_RELIABLE: "+PhoneConfig.AUDIO_RELIABLE); - - if (xml.video_reliable != null && xml.video_reliable.toString() != ""){ - PhoneConfig.VIDEO_RELIABLE = (xml.video_reliable == "true"); - } - Logger.info("VIDEO_RELIABLE: "+PhoneConfig.VIDEO_RELIABLE); - - if (xml.buffer_time != null && xml.buffer_time.toString() != ""){ - PhoneConfig.BUFFER_TIME = Number(xml.buffer_time); - } - Logger.info("BUFFER_TIME: "+PhoneConfig.BUFFER_TIME); - - if (xml.ring_sound != null && xml.ring_sound.toString() != ""){ - SoundControl.RING_SOUND = xml.ring_sound; - } - if (xml.busy_sound != null && xml.busy_sound.toString() != ""){ - SoundControl.BUSY_SOUND = xml.busy_sound; - } - if (xml.register_sound != null && xml.register_sound.toString() != ""){ - SoundControl.REGISTER_SOUND = xml.register_sound; - } - if (xml.finish_sound != null && xml.finish_sound.toString() != ""){ - SoundControl.FINISH_SOUND = xml.finish_sound; - } - - if (xml.load_balancer_url != null && xml.load_balancer_url.toString() !=""){ - PhoneConfig.LOAD_BALANCER_URL = xml.load_balancer_url; - } - - SoundControl.updateSounds(); - } - else - { - Logger.info("Can not load xml settings. Default settings will be used."); - } - initialized = true; - - } - - - public function dropInitTimer():void{ - if (initTimer!=null){ - initTimer.stop(); - initTimer.removeEventListener(TimerEvent.TIMER,init); - initTimer=null; - } - } - - public function startInitTimer():void{ - if (initTimer!=null){ - initTimer.stop(); - - } else { - initTimer = new Timer(1000); - initTimer.addEventListener(TimerEvent.TIMER,init); - } - initTimer.start(); - } - - - } - - -} diff --git a/client/api/src/com/flashphoner/api/PhoneServerProxy.as b/client/api/src/com/flashphoner/api/PhoneServerProxy.as deleted file mode 100644 index b2e2b210..00000000 --- a/client/api/src/com/flashphoner/api/PhoneServerProxy.as +++ /dev/null @@ -1,251 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.adobe.cairngorm.control.CairngormEventDispatcher; - import com.flashphoner.Logger; - import com.flashphoner.api.data.ErrorCodes; - import com.flashphoner.api.data.ModelLocator; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - import com.flashphoner.api.management.VideoControl; - - import flash.events.*; - import flash.net.*; - import flash.system.Security; - import flash.system.SecurityPanel; - import flash.utils.Timer; - import flash.utils.setTimeout; - - import mx.controls.Alert; - - /** - * Media server outgoing communication class - * **/ - internal class PhoneServerProxy - { - //output voice stream - private static var outStream:NetStream; - - private var responder:Responder; - internal var nc:NetConnection; - - public var hasDisconnectAttempt:Boolean; - - public static var sendVideo:Boolean = false; - - public var phoneSpeaker:PhoneSpeaker; - - private var flash_API:Flash_API; - - private var keepAliveTimer:Timer; - - private var keepAliveTimeoutTimer:Timer; - - private var isConnected:Boolean; - - public function PhoneServerProxy(responder:Responder,flash_API:Flash_API) - { - this.flash_API = flash_API; - this.responder = responder; - nc = new NetConnection(); - nc.client = new PhoneCallback(flash_API); - phoneSpeaker = new PhoneSpeaker(nc,flash_API); - isConnected = false; - - } - - public function login(loginObject:Object, WCSUrl:String):int{ - - var modelLocator:ModelLocator = flash_API.modelLocator; - loginObject.registerRequired = PhoneConfig.REGISTER_REQUIRED; - - loginObject.width = PhoneConfig.VIDEO_WIDTH; - loginObject.height = PhoneConfig.VIDEO_HEIGHT; - loginObject.supportedResolutions = PhoneConfig.SUPPORTED_RESOLUTIONS; - - if (loginObject.token == null) { - if (loginObject.authenticationName == null || loginObject.authenticationName == ""){ - loginObject.authenticationName = loginObject.login; - } - loginObject.visibleName = modelLocator.visibleName; - } - createConnection(loginObject, WCSUrl); - return 0; - } - - private function createConnection(obj:Object, WCSUrl:String):void { - Logger.info("createConnection serverUrl: "+WCSUrl); - nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler); - nc.connect(WCSUrl,obj); - } - - public function subscribe(subscribeObj:Object):void{ - Logger.info("subscribe "+subscribeObj); - nc.call("subscribe",null,subscribeObj); - } - - /* - public function loginByTokenWithPageUrl(token:String = null, pageUrl:String):void{ - var modelLocator:ModelLocator = flash_API.modelLocator; - var obj:Object = new Object(); - obj.registerRequired = PhoneConfig.REGISTER_REQUIRED; - obj.token = token; - obj.width = PhoneConfig.VIDEO_WIDTH; - obj.height = PhoneConfig.VIDEO_HEIGHT; - obj.pageUrl = pageUrl; - nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler); - nc.connect(PhoneConfig.SERVER_URL+"/"+PhoneConfig.APP_NAME,obj); - } - */ - - public function call(callObject:Object):void{ - Logger.info("PhoneServerProxy.call()"); - nc.call("call", responder, callObject); - } - - public function callByToken(callObject:Object):void{ - Logger.info("PhoneServerProxy.callByToken()"); - nc.call("call", responder, callObject); - } - - public function msrpCall(callObject:Object):void{ - Logger.info("PhoneServerProxy.msrpCall()"); - nc.call("msrpCall", responder, callObject); - } - public function disconnect():void { - hasDisconnectAttempt = true; - nc.close(); - } - - public function initKeepAlive():void{ - Logger.info("initKeepAlive"); - keepAliveTimer = new Timer(PhoneConfig.KEEP_ALIVE_INTERVAL,1); - keepAliveTimer.addEventListener(TimerEvent.TIMER_COMPLETE,fireKeepAlive); - - keepAliveTimeoutTimer = new Timer(PhoneConfig.KEEP_ALIVE_TIMEOUT,1); - keepAliveTimeoutTimer.addEventListener(TimerEvent.TIMER_COMPLETE,fireKeepAliveTimeout); - Logger.info("keepAliveTimeoutTimer: "+PhoneConfig.KEEP_ALIVE_INTERVAL+" keepAliveTimeoutTimer: "+PhoneConfig.KEEP_ALIVE_TIMEOUT); - } - - public function startKeepAlive():void{ - Logger.debug("startKeepAlive "+new Date()); - keepAliveTimer.start(); - } - - public function fireKeepAlive(event:TimerEvent):void{ - Logger.debug("fireKeepAlive "+new Date()); - nc.call("keepAlive",new Responder(keepAliveResponse)); - keepAliveTimeoutTimer.start(); - } - - public function keepAliveResponse(result:int):void{ - Logger.debug("keepAliveResponse: "+result); - keepAliveTimeoutTimer.stop(); - startKeepAlive(); - } - - public function fireKeepAliveTimeout(event:TimerEvent):void{ - Logger.info("fireKeepAliveTimeout. Close connection by keep alive timeout: "+PhoneConfig.KEEP_ALIVE_TIMEOUT); - nc.close(); - } - - public function netStatusHandler(event : NetStatusEvent) : void - { - var modelLocator:ModelLocator = flash_API.modelLocator; - if(event.info.code == "NetConnection.Connect.Success") - { - Logger.info("NetConnection.Connect.Success"); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyConnected(); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new MainEvent(MainEvent.CONNECTED,flash_API)); - if (PhoneConfig.KEEP_ALIVE){ - initKeepAlive(); - startKeepAlive(); - } - - isConnected = true; - - } else if(event.info.code == "NetConnection.Connect.Failed") - { - Logger.info("NetConnection.Connect.Failed"); - flash_API.dropRegisteredTimer(); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyError(ErrorCodes.CONNECTION_ERROR); - } - hasDisconnectAttempt = false; - } else if (event.info.code == 'NetConnection.Connect.Rejected') - { - Logger.info("NetConnection.Connect.Rejected"); - Alert.show("Connect rejected,\n permission to server denied."); - hasDisconnectAttempt = false; - } else if (event.info.code == 'NetConnection.Connect.Closed') - { - Logger.info("NetConnection.Connect.Closed"); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.notifyCloseConnection(); - } - CairngormEventDispatcher.getInstance().dispatchEvent(new MainEvent(MainEvent.DISCONNECT,flash_API)); - hasDisconnectAttempt = false; - isConnected = false; - } - } - - public function sendInstantMessage(msg:Object):void{ - nc.call("sendInstantMessage",null,msg); - } - - public function notificationResult(notificationResult:Object):void{ - nc.call("notificationResult", null, notificationResult); - } - - public function sendInfo(infoObject:Object):void{ - nc.call("sendInfo", null, infoObject); - } - - public function pushLogs(logs:String):Boolean { - if(isConnected) { - //merge JS and FLASH logs - var logsToServer:String = Logger.merge(logs); - - //clear FLASH logs - Logger.clear(); - - nc.call("pushLogs", null, logsToServer); - return true; - } else { - return false; - } - } - - public function submitBugReport(reportObj:Object){ - if (isConnected){ - nc.call("submitBugReport",null,reportObj); - } - } - - public function pong(){ - nc.call("pong",null); - } - - public function setLTState(stateObj:Object):void{ - nc.call("setLTState", null, stateObj); - } - - public function sendXcapRequest(xcapUrl:String):void{ - nc.call("sendXcapRequest", null, xcapUrl); - } - - } -} diff --git a/client/api/src/com/flashphoner/api/PhoneSpeaker.as b/client/api/src/com/flashphoner/api/PhoneSpeaker.as deleted file mode 100644 index 67634b99..00000000 --- a/client/api/src/com/flashphoner/api/PhoneSpeaker.as +++ /dev/null @@ -1,185 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - - import com.flashphoner.Logger; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - - import flash.events.*; - import flash.media.*; - import flash.net.NetConnection; - import flash.net.NetStream; - - import mx.core.UIComponent; - - /** - * Phone speaker and video window implementation - * **/ - public class PhoneSpeaker extends UIComponent - { - private var videoContainer:UIComponent; - private var video:Video; - private var incomingStream:NetStream; - private var incomingVideoStream:NetStream; - private var netConnection:NetConnection; - /** - * Playing flag - **/ - public var playing:Boolean; - - private var currentVolume:int = 100; - private var streamName:String; - private var rePlay:Boolean = false; - - private var flashAPI:Flash_API; - - /** - * Construstor to create video object - * @param netConnection connection for playing audio and video - **/ - public function PhoneSpeaker(netConnection:NetConnection, flashAPI:Flash_API):void - { - this.flashAPI = flashAPI; - this.netConnection = netConnection; - video = new Video(); - addChild(video); - video.width = 215; - video.height = 138; - video.clear(); - } - - private function nsOnStatus(infoObject:NetStatusEvent):void - { - Logger.info("PhoneSpeaker.nsOnStatus() "+infoObject.info.code); - - if (incomingStream==null){ - return; - } - - if (infoObject.info.code == "NetStream.Play.Start"){ - playing = true; - } - - if (infoObject.info.code == "NetStream.Play.PublishNotify"){ - SoundControl.stopRingSound(); - } - - else if (infoObject.info.code == "NetStream.Play.StreamNotFound" || infoObject.info.code == "NetStream.Play.Failed"||infoObject.info.code == "NetStream.Play.Stop"){ - Logger.info("incomingStream.onStatus() "+infoObject.info.description); - playing = false; - } - - } - - - /** - * Stop playing audio stream for call - * @param callId identifier for call - **/ - public function stop(callId:String):void{ - Logger.info("PhoneSpeaker.stopAudio() - "+callId +"; current stream name - "+streamName); - if (incomingStream!=null && streamName.indexOf(callId) != -1){ - incomingStream.removeEventListener(NetStatusEvent.NET_STATUS,nsOnStatus); - try{ - incomingStream.play(false); - incomingStream.close(); - }catch (e:Error){ - Logger.error(e.message); - } - incomingStream.close(); - incomingStream = null; - playing = false; - video.clear(); - video.attachNetStream(null); - } - } - - /** - * Play audio stream - * @param streamName name of audio stream - **/ - public function play(streamName:String, rePlay:Boolean):void{ - Logger.info("PhoneSpeaker play streamName="+streamName +"; currentStremName="+this.streamName); - //If we have a new stream, we stop old and start new - //This is mandatory for reInvite and update to video session - var needReplay:Boolean = this.rePlay; - this.rePlay = rePlay; - if (incomingStream != null){ - if (this.streamName == streamName && !needReplay){ - return; - } - stop(this.streamName); - } - incomingStream = startNewIncomingStream(streamName,nsOnStatus); - this.streamName = streamName; - } - - private function startNewIncomingStream(streamName:String, listener:Function):NetStream{ - Logger.info("PhoneSpeaker startNewIncomingStream streamName="+streamName); - - var stream:NetStream = new NetStream(netConnection); - - stream.addEventListener(NetStatusEvent.NET_STATUS, listener); - - var streamClientObj:Object = new Object(); - stream.client = streamClientObj; - stream.bufferTime = PhoneConfig.BUFFER_TIME; - - Logger.info("bufferTime "+stream.bufferTime); - - var soundTransform:SoundTransform = new SoundTransform(); - soundTransform.volume=currentVolume/100; - - stream.soundTransform = soundTransform; - stream.play(streamName); - - video.attachNetStream(stream); - - return stream; - } - - /** - * Get current volume for speakers (1-100) - **/ - public function getVolume():int{ - return currentVolume; - } - - /** - * Set current volume for speakers - * @param volume (1-100) - **/ - public function setVolume(volume:int):void{ - currentVolume = volume; - if (incomingStream != null){ - var soundTransform:SoundTransform = new SoundTransform; - soundTransform.volume = currentVolume/100; - incomingStream.soundTransform = soundTransform; - } - - } - - /** - * Change format of a video - * @param format (CIF/QCIF) - **/ - public function changeFormat(width:int, height:int):void{ - this.video.width=width; - this.video.height=height; - this.video.clear(); - } - - } -} diff --git a/client/api/src/com/flashphoner/api/SoundControl.as b/client/api/src/com/flashphoner/api/SoundControl.as deleted file mode 100644 index a42b02df..00000000 --- a/client/api/src/com/flashphoner/api/SoundControl.as +++ /dev/null @@ -1,313 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api -{ - import com.flashphoner.Logger; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.events.ProgressEvent; - import flash.media.Microphone; - import flash.media.Sound; - import flash.media.SoundChannel; - import flash.media.SoundCodec; - import flash.media.SoundTransform; - import flash.net.URLRequest; - import flash.system.Capabilities; - - import flashx.textLayout.events.UpdateCompleteEvent; - - public class SoundControl - { - - [Embed(source="/sounds/CALL_OUT.mp3")] - private static var ringClass:Class; - [Embed(source="/sounds/BUSY.mp3")] - private static var busyClass:Class; - [Embed(source="/sounds/REGISTER.mp3")] - private static var registerClass:Class; - [Embed(source="/sounds/HANGUP.mp3")] - private static var finishClass:Class; - - private static var ringSound:Sound; - private static var busySound:Sound; - private static var registerSound:Sound; - private static var finishSound:Sound; - private static var ringSoundChannel:SoundChannel; - - /** - * Path to sound for ring - **/ - public static var RING_SOUND:String = null; - /** - * Path to sound for busy - **/ - public static var BUSY_SOUND:String = null; - /** - * Path to sound for register event on voip server - **/ - public static var REGISTER_SOUND:String = null; - /** - * Path to sound for finish call - **/ - public static var FINISH_SOUND:String = null; - - private static var soundControl:SoundControl; - - private var mic:Microphone; - - private var flash_API:Flash_API; - - private var majorPlayerVersion:Number=11; - - /** - * Control class (singelton) for microphone and sounds. - **/ - - public function SoundControl(flash_API:Flash_API) - { - this.flash_API = flash_API; - Logger.info("Use enchenced mic: "+PhoneConfig.USE_ENHANCED_MIC); - mic = defineMicrophone(); - - if (mic != null){ - initMic(mic,50,false); - } - } - - - private function defineMicrophone(index:int=-1):Microphone { - Logger.info("getMicrophone "+index); - if (PhoneConfig.USE_ENHANCED_MIC){ - if (PhoneConfig.MAJOR_PLAYER_VERSION >= 11 || Capabilities.language.indexOf("en") >= 0 || PhoneConfig.FORCE_ENHANCED_MIC){ - Logger.info("return EnhancedMicrophone"); - Logger.info("majorVersion: "+PhoneConfig.MAJOR_PLAYER_VERSION); - Logger.info("Capabilities.language: "+Capabilities.language); - Logger.info("FORCE_ENHANCED_MIC: "+PhoneConfig.FORCE_ENHANCED_MIC); - return Microphone.getEnhancedMicrophone(index); - }else{ - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.addLogMessage("WARNING!!! Echo cancellation is turned off on your side (because your OS has no-english localization). Please use a headset to avoid echo for your interlocutor."); - } - Logger.info("return Microphone"); - return Microphone.getMicrophone(index); - } - }else{ - Logger.info("return Microphone"); - return Microphone.getMicrophone(index); - } - } - - /** - * Update all sounds from pathes - **/ - public static function updateSounds():void{ - ringSound = Sound(new ringClass()); - busySound = Sound(new busyClass()); - registerSound = Sound(new registerClass()); - finishSound = Sound(new finishClass()); - - // Create new sounds. We will not check if links != 0, because we plus "" there. - // So it will not create error. Just will empty sounds. - - if (SoundControl.RING_SOUND!=null && SoundControl.RING_SOUND.length!=0){ - updateSound(new Sound(new URLRequest(SoundControl.RING_SOUND))); - } - - if (SoundControl.BUSY_SOUND!=null && SoundControl.BUSY_SOUND.length!=0){ - updateSound(new Sound(new URLRequest(SoundControl.BUSY_SOUND))); - } - - if (SoundControl.REGISTER_SOUND!=null && SoundControl.REGISTER_SOUND.length!=0){ - updateSound(new Sound(new URLRequest(SoundControl.REGISTER_SOUND))); - } - - if (SoundControl.FINISH_SOUND!=null && SoundControl.FINISH_SOUND.length!=0){ - updateSound(new Sound(new URLRequest(SoundControl.FINISH_SOUND))); - } - - } - - private static function updateSound(sound:Sound):void{ - sound.addEventListener(Event.COMPLETE, onUpdateSoundComplete); - sound.addEventListener(IOErrorEvent.IO_ERROR,onUpdateSoundError); - Logger.info("updateSound: "+sound.url); - } - - public static function onUpdateSoundError(event:IOErrorEvent):void{ - Logger.info("Error: "+event.text); - } - - // We are waiting for "complete" event. That mean if link broken and there is - // no sound on that url, complete event will never appear. - // On complete event we are invoking assign function. - // It assign old sounds to new ones. - - public static function onUpdateSoundComplete(event:Event):void{ - - var localSound:Sound = event.target as Sound; - - // For every event we check by what sounds complete event was invoked. - // we check sound url and compare it with all our urls. - // When we found coincidence - we making assignment - - if (localSound.url.indexOf(SoundControl.RING_SOUND) >= 0){ - ringSound = localSound; - } - - if (localSound.url.indexOf(SoundControl.BUSY_SOUND) >= 0) { - busySound = localSound; - } - - if (localSound.url.indexOf(SoundControl.REGISTER_SOUND) >= 0) { - registerSound = localSound; - } - - if (localSound.url.indexOf(SoundControl.FINISH_SOUND) >= 0) { - finishSound = localSound; - } - - Logger.info("onUpdateSoundComplete :"+localSound.url); - } - - /** - * Play busy sound - **/ - public static function playBusySound():void{ - busySound.play(0,1); - } - - /** - * Play finish sound - **/ - public static function playFinishSound():void{ - finishSound.play(0,1); - } - - /** - * Play register sound - **/ - public static function playRegisterSound():void{ - Logger.info("playRegisterSound "+registerSound.url); - registerSound.play(0,1); - } - - /** - * Stop ring sound - **/ - public static function stopRingSound():void{ - if (ringSoundChannel!=null){ - ringSoundChannel.stop(); - ringSoundChannel = null; - } - } - - /** - * Play register sound - **/ - public static function playRingSound():void{ - if (ringSoundChannel == null){ - ringSoundChannel = ringSound.play(0,999); - } - } - - public function isMuted():int{ - if (mic == null){ - return 0; - }else{ - if (mic.muted){ - return 1; - }else{ - return -1; - } - - } - } - - /** - * Change current microphone - * @param index of array - * @param isLoopBack playback voice on speakers - * @param gain volume of microphone(-1 - if not change volume) - **/ - public function changeMicrophone(index:int,isLoopback:Boolean,gain:Number = -1):void{ - Logger.info("changeMicrophone: index "+index+" isLoopback "+isLoopback+" gain: "+gain); - var microphone:Microphone = defineMicrophone(index); - if (microphone != null){ - this.mic = microphone; - if (this.mic != null){ - initMic(mic,gain,isLoopback); - } - } - } - - /** - * Get cuurent microphone - **/ - public function getMicrophone():Microphone{ - return mic; - } - - private function initMic(mic:Microphone, gain:int=50, loopback:Boolean=false):void{ - var logMsg:String = "Init mic: codec: "+PhoneConfig.AUDIO_CODEC+" gain: "+50+" loopback: "+loopback; - Logger.info(logMsg); - for each (var apiNotify:APINotify in Flash_API.apiNotifys){ - apiNotify.addLogMessage(logMsg); - } - - changeCodec(PhoneConfig.AUDIO_CODEC); - - if (gain != -1){ - mic.gain = gain; - } - - mic.soundTransform = new SoundTransform(1,0); - mic.setLoopBack(loopback); - mic.setSilenceLevel(0,3600000); - mic.setUseEchoSuppression(true); - } - - public function changeAudioCodec(codec:Object):void{ - var codecName:String = codec.name; - Logger.info("changeAudioCodec: "+codecName); - changeCodec(codecName); - } - - private function changeCodec(name:String):void{ - Logger.info("changeCodec: "+name); - if (name=="speex"){ - mic.codec = SoundCodec.SPEEX; - mic.framesPerPacket = 1; - mic.rate = 16; - mic.encodeQuality = 6; - }else if (name=="ulaw" || name=="pcmu" ){ - mic.codec = SoundCodec.PCMU; - mic.framesPerPacket = PhoneConfig.G711_FRAMES_PER_PACKET; - mic.rate = 8; - }else if (name=="alaw" || name=="pcma" ){ - mic.codec = SoundCodec.PCMA; - mic.framesPerPacket = PhoneConfig.G711_FRAMES_PER_PACKET; - mic.rate = 8; - } - } - - public function setSpeexQuality(quality:int){ - Logger.info("setSpeexQuality: "+quality); - mic.encodeQuality=quality; - } - - - } -} diff --git a/client/api/src/com/flashphoner/api/data/ErrorCodes.as b/client/api/src/com/flashphoner/api/data/ErrorCodes.as deleted file mode 100644 index 032a6f01..00000000 --- a/client/api/src/com/flashphoner/api/data/ErrorCodes.as +++ /dev/null @@ -1,83 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.data -{ - - /** - * Error codes from server and client side - * **/ - public class ErrorCodes - { - /** - * Authentication on sip server is fail - **/ - public static const AUTHENTICATION_FAIL:String = "AUTHENTICATION_FAIL"; - /** - * User not available on sip server - **/ - public static const USER_NOT_AVAILABLE:String = "USER_NOT_AVAILABLE"; - /** - * Many registration attempts - **/ - public static const TOO_MANY_REGISTER_ATTEMPTS:String = "TOO_MANY_REGISTER_ATTEMPTS"; - /** - * Your license of Flashphoner is trial - **/ - public static const LICENSE_RESTRICTION:String = "LICENSE_RESTRICTION"; - /** - * Your license of Flashphoner not found - **/ - public static const LICENSE_NOT_FOUND:String = "LICENSE_NOT_FOUND"; - /** - * Unknown error on server by sip protocol - **/ - public static const INTERNAL_SIP_ERROR:String = "INTERNAL_SIP_ERROR"; - /** - * Connection with flashphoner-server is not available - **/ - public static const CONNECTION_ERROR:String = "CONNECTION_ERROR"; - /** - * It is client error, throw if answer on registration do not receive from server within 15 seconds - **/ - public static const REGISTER_EXPIRE:String = "REGISTER_EXPIRE"; - /** - * Parameters from file 'flashphoner.xml' is not readed. - * throw when excecute Flash_API.getParameters() - **/ - public static const PARAMETERS_IS_NOT_INITIALIZED:String = "PARAMETERS_IS_NOT_INITIALIZED"; - /** - * All sip ports on flashphoner-server is busy - **/ - public static const SIP_PORTS_BUSY:String = "SIP_PORTS_BUSY"; - /** - * All sip ports on flashphoner-server is busy - **/ - public static const MEDIA_PORTS_BUSY:String = "MEDIA_PORTS_BUSY"; - /** - * flashphoner server can not connect with sip provider server. - **/ - public static const WRONG_SIPPROVIDER_ADDRESS:String = "WRONG_SIPPROVIDER_ADDRESS"; - /** - * Application can`t load flashphoner.xml properly - **/ - public static const WRONG_FLASHPHONER_XML:String = "WRONG_FLASHPHONER_XML"; - /** - * Callee name is null. - **/ - public static const CALLEE_NAME_IS_NULL:String = "CALLEE_NAME_IS_NULL"; - /** - * Payments required from user. SIP 402 Payment Required - **/ - public static const PAYMENT_REQUIRED:String = "PAYMENT_REQUIRED"; - } -} diff --git a/client/api/src/com/flashphoner/api/data/ModelLocator.as b/client/api/src/com/flashphoner/api/data/ModelLocator.as deleted file mode 100644 index f27fd1bd..00000000 --- a/client/api/src/com/flashphoner/api/data/ModelLocator.as +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.data -{ - [Bindable] - /** - * Class used to store information about connected user - **/ - public class ModelLocator - { - /** - * Login of user - */ - public var login:String = ''; - /** - * Password of user - **/ - public var pwd:String = null; - /** - * Host of sip provider (example: sipnet.ru) - */ - public var outboundProxy:String; - - public var domain:String; - /** - * Port of sip provider (default - 5060) - **/ - public var port:String; - /** - * Visible name of user - **/ - public var visibleName:String = ""; - /** - * Logged user on sip provider or no - */ - public var logged:Boolean = false; - } -} diff --git a/client/api/src/com/flashphoner/api/data/PhoneConfig.as b/client/api/src/com/flashphoner/api/data/PhoneConfig.as deleted file mode 100644 index 13e3d37d..00000000 --- a/client/api/src/com/flashphoner/api/data/PhoneConfig.as +++ /dev/null @@ -1,134 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.data -{ - import flash.events.*; - import flash.net.*; - [Bindable] - /** - * Confiruration parameters from file flashphoner.xml - **/ - public class PhoneConfig - { - /** - * Width of outgoing video - **/ - public static var VIDEO_WIDTH:int = 176; - - /** - * Height of outgoing video - **/ - public static var VIDEO_HEIGHT:int = 144; - - /** - * Size of buffer in incomming video - **/ - public static var BUFFER_TIME:Number = 0; - - /** - * Is User Agent on VoIP server required (true/false) - **/ - public static var REGISTER_REQUIRED:Boolean = true; - - /** - * Is videocalls support enabled (true/false) - **/ - public static var VIDEO_ENABLED:Boolean = true; - - /** - * Is callee validation enabled (true/false) - **/ - public static var CHECK_VALIDATION_CALLEE:Boolean = true; - - /** - * Is use enhansed mic for echo supression (true/false) - **/ - public static var USE_ENHANCED_MIC:Boolean = true; - - /** - * Always use enhanced mic, regardless of Player version or locale - **/ - public static var FORCE_ENHANCED_MIC:Boolean = false; - - /** - * Current version of Flashphoner client - **/ - public static var VERSION_OF_CLIENT:String = "1.0.X"; - - /** - * Current version of Flashphoner server - **/ - public static var VERSION_OF_SERVER:String = "1.0.5.X"; - - public static var AUDIO_CODEC:String = "speex"; - - public static var KEEP_ALIVE:Boolean = false; - - public static var KEEP_ALIVE_INTERVAL:int = 1000; - - public static var KEEP_ALIVE_TIMEOUT:int = 5000; - - public static var PUSH_LOG:Boolean = false; - - public static var LOG_SEVERITY:String = "INFO"; - - public static var MAJOR_PLAYER_VERSION:int = 11; - - public static var AVOID_FLV2H264_TRANSCODING:Boolean = true; - - public static var VIDEO_RELIABLE = false; - - public static var AUDIO_RELIABLE = false; - - public static var LOAD_BALANCER_URL = null; - - public static var WCS_SERVER:String = "192.168.1.5"; - - public static var RTMFP_PORT:int = 1935; - - /** - * 1 - 10 ms - * 2 - 20 ms by default - * The setting may be required if you need to change ptime interval for G.711. - **/ - public static var G711_FRAMES_PER_PACKET:int = 2; - - /** - * Current version of Flashphoner product - **/ - public static function getFullVersion():String{ - var client:String = "X"; - var indexClient:int = VERSION_OF_CLIENT.lastIndexOf("."); - if (indexClient > -1){ - client = VERSION_OF_CLIENT.substring(indexClient+1); - } - - var indexServer:int = VERSION_OF_SERVER.lastIndexOf(".") - var server:String = "X"; - if (indexServer > -1){ - server = VERSION_OF_SERVER.substring(indexServer+1); - } - return client+"-"+server; - } - - public static function getRandomInt(from:int, to:int):int{ - return int(Math.floor( from + ( Math.random() * ( to - from + 1)))); - } - - /** - * Resolutions which supported camera - **/ - public static var SUPPORTED_RESOLUTIONS:String =""; - - } -} diff --git a/client/api/src/com/flashphoner/api/interfaces/API.as b/client/api/src/com/flashphoner/api/interfaces/API.as deleted file mode 100644 index c331d814..00000000 --- a/client/api/src/com/flashphoner/api/interfaces/API.as +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.interfaces -{ - public interface API - { - function addAPINotify(apiNotify:APINotify):void; - function getAPINotify():APINotify; - function getParameters():Object; - function login(username:String,password:String):int; - function call(callee:String, visibleName:String, isVideoCall:Boolean = false):int; - function hangup():void; - function setStatusHold(isHold:Boolean):void; - function transfer(callee:String):void; - function answer(isVideoCall:Boolean = false):void; - function isSendVideo(flag:Boolean):void; - function sendDTMF(dtmf:String):void; - function getMicVolume():int; - function setMicVolume(volume:int):void; - function getMicropones():Array; - function setMicrophone(name:String):void; - function getCameras():Array; - function setCamera(name:String):void; - function getVolume():int; - function setVolume(volume:int):void; - function logoff():void; - } -} diff --git a/client/api/src/com/flashphoner/api/interfaces/APINotify.as b/client/api/src/com/flashphoner/api/interfaces/APINotify.as deleted file mode 100644 index f72a66f5..00000000 --- a/client/api/src/com/flashphoner/api/interfaces/APINotify.as +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.interfaces -{ - import com.flashphoner.api.Call; - - public interface APINotify - { - function notifyCloseConnection():void; - function notifyConnected():void; - function notifyRegistered(_sipObject:Object):void; - function notifyCallbackHold(call:Call,isHold:Boolean):void; - function notify(call:Call,_sipObject:Object):void; - function notifyCost(call:Call,cost:Number):void; - function notifyBalance(balance:Number,_sipObject:Object):void; - function notifyBugReport(filename:String):void; - function notifyError(error:String,_sipObject:Object = null):void; - function notifyVideoFormat(videoFormat:Object,_sipObject:Object = null):void; - function notifyOpenVideoView(isViewed:Boolean):void; - function notifyMessage(messageObject:Object, notifyMessageResult:Object, sipObject:Object):void; - function notifyAddCall(call:Call):void; - function notifyRemoveCall(call:Call):void; - function notifySubscription(subscribtionObj:Object, sipObj:Object):void; - - function addLogMessage(message:String):void; - function notifyVersion(version:String):void; - function notifyXcapResponse(xcapResponse:String):void; - } -} diff --git a/client/api/src/com/flashphoner/api/js/APINotifyJS.as b/client/api/src/com/flashphoner/api/js/APINotifyJS.as deleted file mode 100644 index 2512ce44..00000000 --- a/client/api/src/com/flashphoner/api/js/APINotifyJS.as +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.js -{ - import com.flashphoner.api.Call; - import com.flashphoner.api.interfaces.APINotify; - - import flash.external.ExternalInterface; - - /** - * Implementaion interface for js-phones - **/ - public class APINotifyJS implements APINotify - { - public function APINotifyJS() - { - } - public function notifyCloseConnection():void{ - ExternalInterface.call("notifyCloseConnection"); - } - public function notifyConnected():void{ - ExternalInterface.call("notifyConnected"); - } - public function notifyRegistered(_sipObject:Object):void{ - ExternalInterface.call("notifyRegistered", _sipObject); - } - public function notifyBalance(balance:Number,_sipObject:Object):void{ - ExternalInterface.call("notifyBalance",String(balance)); - } - public function notifyBugReport(filename:String):void{ - ExternalInterface.call("notifyBugReport",filename); - } - public function notify(call:Call,_sipObject:Object):void{ - ExternalInterface.call("notify",call, _sipObject); - } - public function notifyCallbackHold(call:Call,isHold:Boolean):void{ - ExternalInterface.call("notifyCallbackHold",call,isHold); - } - - public function notifyCost(call:Call,cost:Number):void{ - ExternalInterface.call("notifyCost",call.id,String(cost)); - } - - public function notifyError(error:String,_sipObject:Object = null):void{ - ExternalInterface.call("notifyError",error); - } - - public function notifyVideoFormat(videoFormat:Object,_sipObject:Object = null):void{ - ExternalInterface.call("notifyVideoFormat",videoFormat); - } - - public function notifyOpenVideoView(isViewed:Boolean):void{ - ExternalInterface.call("notifyOpenVideoView",isViewed); - } - - public function notifyMessage(messageObject:Object, notifyMessageResult:Object, sipObject:Object):void{ - ExternalInterface.call("notifyMessage",messageObject, notifyMessageResult, sipObject); - } - - public function notifyAddCall(call:Call):void{ - ExternalInterface.call("notifyAddCall",call); - } - - public function notifyRemoveCall(call:Call):void{ - ExternalInterface.call("notifyRemoveCall",call); - } - - public function notifySubscription(subscribtionObj:Object, sipObj:Object):void { - ExternalInterface.call("notifySubscription", subscribtionObj, sipObj); - } - - public function addLogMessage(message:String):void{ - ExternalInterface.call("addLogMessage", message); - } - - public function notifyVersion(version:String):void{ - ExternalInterface.call("notifyVersion", version); - } - - public function notifyXcapResponse(xcapResponse:String):void{ - ExternalInterface.call("notifyXcapResponse", xcapResponse); - } - - } -} diff --git a/client/api/src/com/flashphoner/api/management/VideoControl.as b/client/api/src/com/flashphoner/api/management/VideoControl.as deleted file mode 100644 index 7fc25eb7..00000000 --- a/client/api/src/com/flashphoner/api/management/VideoControl.as +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.api.management -{ - import com.flashphoner.Logger; - import com.flashphoner.api.data.PhoneConfig; - - import flash.media.Camera; - - import flashx.textLayout.debug.assert; - - import mx.controls.Alert; - import mx.core.Application; - - /** - * Control class (singelton) for cameras - **/ - public class VideoControl - { - private static var videoControl:VideoControl; - private var cam:Camera; - private const FPS:int = 15; - private const KEEP_RATIO:Boolean = true; - private const KEY_INT:int = 48; - private const QUALITY:int = 80; - - public function VideoControl() - { - cam = Camera.getCamera(); - - } - - /** - * Init width,height,fps and another parameters - **/ - public function init():void{ - if (cam != null){ - supportedResolutions("1280x720,720x576,720x480,640x480,352x576,352x480,352x288,320x240,176x144,160x120,128x96,80x60"); - cam.setMode(PhoneConfig.VIDEO_WIDTH,PhoneConfig.VIDEO_HEIGHT,FPS,KEEP_RATIO); - cam.setKeyFrameInterval(KEY_INT); - cam.setQuality(0,QUALITY); - cam.setMotionLevel(0,2000); - PhoneConfig.VIDEO_WIDTH = cam.width; - PhoneConfig.VIDEO_HEIGHT = cam.height; - } - - } - - /** - * Add new supported resolutions - **/ - public function supportedResolutions(resolutions:String):void { - var supportedResolutions:String = ""; - var resolutionsSplit:Array = resolutions.split(","); - var flag:Boolean = true; - for (var i:int=0;i0)&&(height>0)){ - cam.setMode(width,height,FPS,KEEP_RATIO); - } - } - - public function isMuted():int{ - if (cam == null){ - return 0; - }else{ - if (cam.muted){ - return 1; - }else{ - return -1; - } - - } - } - - /** - * change current camera to used Flashphoner - **/ - public function changeCamera(camera:Camera):void{ - Logger.info("changeCamera"); - if (PhoneConfig.VIDEO_ENABLED){ - camera.setMode(320,240,FPS,KEEP_RATIO); - camera.setKeyFrameInterval(KEY_INT); - camera.setQuality(0,QUALITY); - camera.setMotionLevel(0,2000); - this.cam = camera; - } - } - } -} diff --git a/client/api/src/sounds/BUSY.mp3 b/client/api/src/sounds/BUSY.mp3 deleted file mode 100644 index d34b898c..00000000 Binary files a/client/api/src/sounds/BUSY.mp3 and /dev/null differ diff --git a/client/api/src/sounds/CALL_IN.mp3 b/client/api/src/sounds/CALL_IN.mp3 deleted file mode 100644 index fbf48317..00000000 Binary files a/client/api/src/sounds/CALL_IN.mp3 and /dev/null differ diff --git a/client/api/src/sounds/CALL_OUT.mp3 b/client/api/src/sounds/CALL_OUT.mp3 deleted file mode 100644 index 99db3ee6..00000000 Binary files a/client/api/src/sounds/CALL_OUT.mp3 and /dev/null differ diff --git a/client/api/src/sounds/HANGUP.mp3 b/client/api/src/sounds/HANGUP.mp3 deleted file mode 100644 index 6ff02d87..00000000 Binary files a/client/api/src/sounds/HANGUP.mp3 and /dev/null differ diff --git a/client/api/src/sounds/REGISTER.mp3 b/client/api/src/sounds/REGISTER.mp3 deleted file mode 100644 index 2df86da9..00000000 Binary files a/client/api/src/sounds/REGISTER.mp3 and /dev/null differ diff --git a/client/client/.actionScriptProperties b/client/client/.actionScriptProperties deleted file mode 100644 index 968a490f..00000000 --- a/client/client/.actionScriptProperties +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/client/.flexProperties b/client/client/.flexProperties deleted file mode 100644 index a230c4a2..00000000 --- a/client/client/.flexProperties +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/client/client/.project b/client/client/.project deleted file mode 100644 index 82625292..00000000 --- a/client/client/.project +++ /dev/null @@ -1,25 +0,0 @@ - - - client - - - - - - com.adobe.flexbuilder.project.flexbuilder - - - - - - com.adobe.flexbuilder.project.flexnature - com.adobe.flexbuilder.project.actionscriptnature - - - - bin-debug - 2 - DOCUMENTS/output - - - diff --git a/client/client/.settings/com.adobe.flexbuilder.project.prefs b/client/client/.settings/com.adobe.flexbuilder.project.prefs deleted file mode 100644 index 438ebc79..00000000 --- a/client/client/.settings/com.adobe.flexbuilder.project.prefs +++ /dev/null @@ -1,5 +0,0 @@ -#Tue Jun 05 12:04:51 NOVST 2012 -eclipse.preferences.version=1 -instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true -upgradeSDK/fb4= -useFlex3CompatibilityMode/fb4=true diff --git a/client/client/.settings/org.eclipse.core.resources.prefs b/client/client/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 8540fbb9..00000000 --- a/client/client/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Fri Jul 30 11:09:30 NOVST 2010 -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/client/client/.settings/org.eclipse.ltk.core.refactoring.prefs b/client/client/.settings/org.eclipse.ltk.core.refactoring.prefs deleted file mode 100644 index ef3d5c3d..00000000 --- a/client/client/.settings/org.eclipse.ltk.core.refactoring.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Wed Aug 18 17:17:59 NOVST 2010 -eclipse.preferences.version=1 -org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false diff --git a/client/client/build.properties b/client/client/build.properties deleted file mode 100644 index febf7d07..00000000 --- a/client/client/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -FLEX_HOME_WINDOWS=C:/Program Files/Adobe/Adobe Flash Builder 4/sdks/3.4 -FLEX_HOME_LINUX=/opt/flex -PLAYER_VERSION=11.0 -SWF_VERSION=13 \ No newline at end of file diff --git a/client/client/build.xml b/client/client/build.xml deleted file mode 100644 index 2a9453c7..00000000 --- a/client/client/build.xml +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/client/client/src/Click2callJS.html b/client/client/src/Click2callJS.html deleted file mode 100644 index bc85c172..00000000 --- a/client/client/src/Click2callJS.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click2Call - - - -
- -
- -
- -
Support
-
- - -
- - -
-
-
Hangup
-
-
-
- - -
-
-
-
1
-
2
-
3
-
-
-
4
-
5
-
6
-
-
-
7
-
8
-
9
-
-
-
*
-
0
-
#
-
-
- - -
-
-
-
- -
- - -
-
- Click "Allow" to continue -
- - - -
-
-
- - -
-
-
- - - -
- -
- - -
- - -
Mic / Cam settings
- -
- - - - - - - - -
Ok
-
- - - - - diff --git a/client/client/src/Phone.html b/client/client/src/Phone.html deleted file mode 100644 index 51564766..00000000 --- a/client/client/src/Phone.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - -Flash phone - - - - - - -
- - Get Adobe Flash player - -
- - - - diff --git a/client/client/src/PhoneJS.html b/client/client/src/PhoneJS.html deleted file mode 100644 index 8b91be95..00000000 --- a/client/client/src/PhoneJS.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Phone - - - - -
- - -
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
- - - -
Log in
-
-
Log out
- -
- - - - -
- -
Video Call
-
- - - - - -
-
Chat
-
Call
-
- -
-
1
-
2
-
3
-
- -
-
4
-
5
-
6
-
- -
-
7
-
8
-
9
-
- -
-
*
-
0
-
#
-
- -
-
- - - -
-
  Login
- - - - - - - - - - - - - - - - - - - -
Log in
-
Cancel
-
-
- - - - -
-
  Incoming call
-
Caller
- is calling you -
Answer
-
Hangup
-
-
- - - -
-
Connecting...
-
- -
-
-
- - - -
-
  Security panel
-
Please allow access to devices
-
- -
-
- - -
-
- - - -
- - - -
-
  Transfer
- Transfer this call to - - -
Ok
-
Cancel
-
-
- - - -
-
  Chat
-
    -
  • -
-
-
-
- - - -
-
-
-
-
-
- - - -
-
- - - -
-
Submit Bug Report
-
- - - -
Test -
- - - - diff --git a/client/client/src/assets/background_phone.png b/client/client/src/assets/background_phone.png deleted file mode 100644 index 8c17d215..00000000 Binary files a/client/client/src/assets/background_phone.png and /dev/null differ diff --git a/client/client/src/assets/c2c_camera.png b/client/client/src/assets/c2c_camera.png deleted file mode 100644 index 7b08ea18..00000000 Binary files a/client/client/src/assets/c2c_camera.png and /dev/null differ diff --git a/client/client/src/assets/c2c_dialpad.png b/client/client/src/assets/c2c_dialpad.png deleted file mode 100644 index a7baf33e..00000000 Binary files a/client/client/src/assets/c2c_dialpad.png and /dev/null differ diff --git a/client/client/src/assets/c2c_mic.png b/client/client/src/assets/c2c_mic.png deleted file mode 100644 index 988f74cf..00000000 Binary files a/client/client/src/assets/c2c_mic.png and /dev/null differ diff --git a/client/client/src/assets/c2c_pause.png b/client/client/src/assets/c2c_pause.png deleted file mode 100644 index b3518ce4..00000000 Binary files a/client/client/src/assets/c2c_pause.png and /dev/null differ diff --git a/client/client/src/assets/c2c_play.png b/client/client/src/assets/c2c_play.png deleted file mode 100644 index 47ba131b..00000000 Binary files a/client/client/src/assets/c2c_play.png and /dev/null differ diff --git a/client/client/src/assets/camera.png b/client/client/src/assets/camera.png deleted file mode 100644 index 685d9989..00000000 Binary files a/client/client/src/assets/camera.png and /dev/null differ diff --git a/client/client/src/assets/hold.png b/client/client/src/assets/hold.png deleted file mode 100644 index 2d9ce9c4..00000000 Binary files a/client/client/src/assets/hold.png and /dev/null differ diff --git a/client/client/src/assets/hold_big.png b/client/client/src/assets/hold_big.png deleted file mode 100644 index b936dbe4..00000000 Binary files a/client/client/src/assets/hold_big.png and /dev/null differ diff --git a/client/client/src/assets/mic.png b/client/client/src/assets/mic.png deleted file mode 100644 index c162e7d6..00000000 Binary files a/client/client/src/assets/mic.png and /dev/null differ diff --git a/client/client/src/assets/mic_crossed.png b/client/client/src/assets/mic_crossed.png deleted file mode 100644 index 712a4f83..00000000 Binary files a/client/client/src/assets/mic_crossed.png and /dev/null differ diff --git a/client/client/src/assets/mic_settings.png b/client/client/src/assets/mic_settings.png deleted file mode 100644 index 67de2c6c..00000000 Binary files a/client/client/src/assets/mic_settings.png and /dev/null differ diff --git a/client/client/src/assets/mic_settings_background.png b/client/client/src/assets/mic_settings_background.png deleted file mode 100644 index 41b0698d..00000000 Binary files a/client/client/src/assets/mic_settings_background.png and /dev/null differ diff --git a/client/client/src/assets/pie/PIE.htc b/client/client/src/assets/pie/PIE.htc deleted file mode 100644 index ca3b5470..00000000 --- a/client/client/src/assets/pie/PIE.htc +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - diff --git a/client/client/src/assets/pie/PIE.js b/client/client/src/assets/pie/PIE.js deleted file mode 100644 index d36448a9..00000000 --- a/client/client/src/assets/pie/PIE.js +++ /dev/null @@ -1,88 +0,0 @@ -/* -PIE: CSS3 rendering for IE -Version 1.0.0 -http://css3pie.com -Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. -*/ -(function(){ -var doc = document;var f=window.PIE; -if(!f){f=window.PIE={F:"-pie-",nb:"Pie",La:"pie_",Ac:{TD:1,TH:1},cc:{TABLE:1,THEAD:1,TBODY:1,TFOOT:1,TR:1,INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,IMG:1,HR:1},fc:{A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},Gd:{submit:1,button:1,reset:1},aa:function(){}};try{doc.execCommand("BackgroundImageCache",false,true)}catch(aa){}for(var ba=4,Z=doc.createElement("div"),ca=Z.getElementsByTagName("i"),ga;Z.innerHTML=" - - - - - - - - diff --git a/client/client/src/assets/pie/PIE_uncompressed.js b/client/client/src/assets/pie/PIE_uncompressed.js deleted file mode 100644 index 85f6785e..00000000 --- a/client/client/src/assets/pie/PIE_uncompressed.js +++ /dev/null @@ -1,4474 +0,0 @@ -/* -PIE: CSS3 rendering for IE -Version 1.0.0 -http://css3pie.com -Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. -*/ -(function(){ -var doc = document;var PIE = window['PIE']; - -if( !PIE ) { - PIE = window['PIE'] = { - CSS_PREFIX: '-pie-', - STYLE_PREFIX: 'Pie', - CLASS_PREFIX: 'pie_', - tableCellTags: { - 'TD': 1, - 'TH': 1 - }, - - /** - * Lookup table of elements which cannot take custom children. - */ - childlessElements: { - 'TABLE':1, - 'THEAD':1, - 'TBODY':1, - 'TFOOT':1, - 'TR':1, - 'INPUT':1, - 'TEXTAREA':1, - 'SELECT':1, - 'OPTION':1, - 'IMG':1, - 'HR':1 - }, - - /** - * Elements that can receive user focus - */ - focusableElements: { - 'A':1, - 'INPUT':1, - 'TEXTAREA':1, - 'SELECT':1, - 'BUTTON':1 - }, - - /** - * Values of the type attribute for input elements displayed as buttons - */ - inputButtonTypes: { - 'submit':1, - 'button':1, - 'reset':1 - }, - - emptyFn: function() {} - }; - - // Force the background cache to be used. No reason it shouldn't be. - try { - doc.execCommand( 'BackgroundImageCache', false, true ); - } catch(e) {} - - (function() { - /* - * IE version detection approach by James Padolsey, with modifications -- from - * http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/ - */ - var ieVersion = 4, - div = doc.createElement('div'), - all = div.getElementsByTagName('i'), - shape; - while ( - div.innerHTML = '', - all[0] - ) {} - PIE.ieVersion = ieVersion; - - // Detect IE6 - if( ieVersion === 6 ) { - // IE6 can't access properties with leading dash, but can without it. - PIE.CSS_PREFIX = PIE.CSS_PREFIX.replace( /^-/, '' ); - } - - PIE.ieDocMode = doc.documentMode || PIE.ieVersion; - - // Detect VML support (a small number of IE installs don't have a working VML engine) - div.innerHTML = ''; - shape = div.firstChild; - shape.style['behavior'] = 'url(#default#VML)'; - PIE.supportsVML = (typeof shape['adj'] === "object"); - }()); -/** - * Utility functions - */ -(function() { - var vmlCreatorDoc, - idNum = 0, - imageSizes = {}; - - - PIE.Util = { - - /** - * To create a VML element, it must be created by a Document which has the VML - * namespace set. Unfortunately, if you try to add the namespace programatically - * into the main document, you will get an "Unspecified error" when trying to - * access document.namespaces before the document is finished loading. To get - * around this, we create a DocumentFragment, which in IE land is apparently a - * full-fledged Document. It allows adding namespaces immediately, so we add the - * namespace there and then have it create the VML element. - * @param {string} tag The tag name for the VML element - * @return {Element} The new VML element - */ - createVmlElement: function( tag ) { - var vmlPrefix = 'css3vml'; - if( !vmlCreatorDoc ) { - vmlCreatorDoc = doc.createDocumentFragment(); - vmlCreatorDoc.namespaces.add( vmlPrefix, 'urn:schemas-microsoft-com:vml' ); - } - return vmlCreatorDoc.createElement( vmlPrefix + ':' + tag ); - }, - - - /** - * Generate and return a unique ID for a given object. The generated ID is stored - * as a property of the object for future reuse. - * @param {Object} obj - */ - getUID: function( obj ) { - return obj && obj[ '_pieId' ] || ( obj[ '_pieId' ] = '_' + ++idNum ); - }, - - - /** - * Simple utility for merging objects - * @param {Object} obj1 The main object into which all others will be merged - * @param {...Object} var_args Other objects which will be merged into the first, in order - */ - merge: function( obj1 ) { - var i, len, p, objN, args = arguments; - for( i = 1, len = args.length; i < len; i++ ) { - objN = args[i]; - for( p in objN ) { - if( objN.hasOwnProperty( p ) ) { - obj1[ p ] = objN[ p ]; - } - } - } - return obj1; - }, - - - /** - * Execute a callback function, passing it the dimensions of a given image once - * they are known. - * @param {string} src The source URL of the image - * @param {function({w:number, h:number})} func The callback function to be called once the image dimensions are known - * @param {Object} ctx A context object which will be used as the 'this' value within the executed callback function - */ - withImageSize: function( src, func, ctx ) { - var size = imageSizes[ src ], img, queue; - if( size ) { - // If we have a queue, add to it - if( Object.prototype.toString.call( size ) === '[object Array]' ) { - size.push( [ func, ctx ] ); - } - // Already have the size cached, call func right away - else { - func.call( ctx, size ); - } - } else { - queue = imageSizes[ src ] = [ [ func, ctx ] ]; //create queue - img = new Image(); - img.onload = function() { - size = imageSizes[ src ] = { w: img.width, h: img.height }; - for( var i = 0, len = queue.length; i < len; i++ ) { - queue[ i ][ 0 ].call( queue[ i ][ 1 ], size ); - } - img.onload = null; - }; - img.src = src; - } - } - }; -})();/** - * Utility functions for handling gradients - */ -PIE.GradientUtil = { - - getGradientMetrics: function( el, width, height, gradientInfo ) { - var angle = gradientInfo.angle, - startPos = gradientInfo.gradientStart, - startX, startY, - endX, endY, - startCornerX, startCornerY, - endCornerX, endCornerY, - deltaX, deltaY, - p, UNDEF; - - // Find the "start" and "end" corners; these are the corners furthest along the gradient line. - // This is used below to find the start/end positions of the CSS3 gradient-line, and also in finding - // the total length of the VML rendered gradient-line corner to corner. - function findCorners() { - startCornerX = ( angle >= 90 && angle < 270 ) ? width : 0; - startCornerY = angle < 180 ? height : 0; - endCornerX = width - startCornerX; - endCornerY = height - startCornerY; - } - - // Normalize the angle to a value between [0, 360) - function normalizeAngle() { - while( angle < 0 ) { - angle += 360; - } - angle = angle % 360; - } - - // Find the start and end points of the gradient - if( startPos ) { - startPos = startPos.coords( el, width, height ); - startX = startPos.x; - startY = startPos.y; - } - if( angle ) { - angle = angle.degrees(); - - normalizeAngle(); - findCorners(); - - // If no start position was specified, then choose a corner as the starting point. - if( !startPos ) { - startX = startCornerX; - startY = startCornerY; - } - - // Find the end position by extending a perpendicular line from the gradient-line which - // intersects the corner opposite from the starting corner. - p = PIE.GradientUtil.perpendicularIntersect( startX, startY, angle, endCornerX, endCornerY ); - endX = p[0]; - endY = p[1]; - } - else if( startPos ) { - // Start position but no angle specified: find the end point by rotating 180deg around the center - endX = width - startX; - endY = height - startY; - } - else { - // Neither position nor angle specified; create vertical gradient from top to bottom - startX = startY = endX = 0; - endY = height; - } - deltaX = endX - startX; - deltaY = endY - startY; - - if( angle === UNDEF ) { - // Get the angle based on the change in x/y from start to end point. Checks first for horizontal - // or vertical angles so they get exact whole numbers rather than what atan2 gives. - angle = ( !deltaX ? ( deltaY < 0 ? 90 : 270 ) : - ( !deltaY ? ( deltaX < 0 ? 180 : 0 ) : - -Math.atan2( deltaY, deltaX ) / Math.PI * 180 - ) - ); - normalizeAngle(); - findCorners(); - } - - return { - angle: angle, - startX: startX, - startY: startY, - endX: endX, - endY: endY, - startCornerX: startCornerX, - startCornerY: startCornerY, - endCornerX: endCornerX, - endCornerY: endCornerY, - deltaX: deltaX, - deltaY: deltaY, - lineLength: PIE.GradientUtil.distance( startX, startY, endX, endY ) - } - }, - - /** - * Find the point along a given line (defined by a starting point and an angle), at which - * that line is intersected by a perpendicular line extending through another point. - * @param x1 - x coord of the starting point - * @param y1 - y coord of the starting point - * @param angle - angle of the line extending from the starting point (in degrees) - * @param x2 - x coord of point along the perpendicular line - * @param y2 - y coord of point along the perpendicular line - * @return [ x, y ] - */ - perpendicularIntersect: function( x1, y1, angle, x2, y2 ) { - // Handle straight vertical and horizontal angles, for performance and to avoid - // divide-by-zero errors. - if( angle === 0 || angle === 180 ) { - return [ x2, y1 ]; - } - else if( angle === 90 || angle === 270 ) { - return [ x1, y2 ]; - } - else { - // General approach: determine the Ax+By=C formula for each line (the slope of the second - // line is the negative inverse of the first) and then solve for where both formulas have - // the same x/y values. - var a1 = Math.tan( -angle * Math.PI / 180 ), - c1 = a1 * x1 - y1, - a2 = -1 / a1, - c2 = a2 * x2 - y2, - d = a2 - a1, - endX = ( c2 - c1 ) / d, - endY = ( a1 * c2 - a2 * c1 ) / d; - return [ endX, endY ]; - } - }, - - /** - * Find the distance between two points - * @param {Number} p1x - * @param {Number} p1y - * @param {Number} p2x - * @param {Number} p2y - * @return {Number} the distance - */ - distance: function( p1x, p1y, p2x, p2y ) { - var dx = p2x - p1x, - dy = p2y - p1y; - return Math.abs( - dx === 0 ? dy : - dy === 0 ? dx : - Math.sqrt( dx * dx + dy * dy ) - ); - } - -};/** - * - */ -PIE.Observable = function() { - /** - * List of registered observer functions - */ - this.observers = []; - - /** - * Hash of function ids to their position in the observers list, for fast lookup - */ - this.indexes = {}; -}; -PIE.Observable.prototype = { - - observe: function( fn ) { - var id = PIE.Util.getUID( fn ), - indexes = this.indexes, - observers = this.observers; - if( !( id in indexes ) ) { - indexes[ id ] = observers.length; - observers.push( fn ); - } - }, - - unobserve: function( fn ) { - var id = PIE.Util.getUID( fn ), - indexes = this.indexes; - if( id && id in indexes ) { - delete this.observers[ indexes[ id ] ]; - delete indexes[ id ]; - } - }, - - fire: function() { - var o = this.observers, - i = o.length; - while( i-- ) { - o[ i ] && o[ i ](); - } - } - -};/* - * Simple heartbeat timer - this is a brute-force workaround for syncing issues caused by IE not - * always firing the onmove and onresize events when elements are moved or resized. We check a few - * times every second to make sure the elements have the correct position and size. See Element.js - * which adds heartbeat listeners based on the custom -pie-poll flag, which defaults to true in IE8-9 - * and false elsewhere. - */ - -PIE.Heartbeat = new PIE.Observable(); -PIE.Heartbeat.run = function() { - var me = this, - interval; - if( !me.running ) { - interval = doc.documentElement.currentStyle.getAttribute( PIE.CSS_PREFIX + 'poll-interval' ) || 250; - (function beat() { - me.fire(); - setTimeout(beat, interval); - })(); - me.running = 1; - } -}; -/** - * Create an observable listener for the onunload event - */ -(function() { - PIE.OnUnload = new PIE.Observable(); - - function handleUnload() { - PIE.OnUnload.fire(); - window.detachEvent( 'onunload', handleUnload ); - window[ 'PIE' ] = null; - } - - window.attachEvent( 'onunload', handleUnload ); - - /** - * Attach an event which automatically gets detached onunload - */ - PIE.OnUnload.attachManagedEvent = function( target, name, handler ) { - target.attachEvent( name, handler ); - this.observe( function() { - target.detachEvent( name, handler ); - } ); - }; -})()/** - * Create a single observable listener for window resize events. - */ -PIE.OnResize = new PIE.Observable(); - -PIE.OnUnload.attachManagedEvent( window, 'onresize', function() { PIE.OnResize.fire(); } ); -/** - * Create a single observable listener for scroll events. Used for lazy loading based - * on the viewport, and for fixed position backgrounds. - */ -(function() { - PIE.OnScroll = new PIE.Observable(); - - function scrolled() { - PIE.OnScroll.fire(); - } - - PIE.OnUnload.attachManagedEvent( window, 'onscroll', scrolled ); - - PIE.OnResize.observe( scrolled ); -})(); -/** - * Listen for printing events, destroy all active PIE instances when printing, and - * restore them afterward. - */ -(function() { - - var elements; - - function beforePrint() { - elements = PIE.Element.destroyAll(); - } - - function afterPrint() { - if( elements ) { - for( var i = 0, len = elements.length; i < len; i++ ) { - PIE[ 'attach' ]( elements[i] ); - } - elements = 0; - } - } - - if( PIE.ieDocMode < 9 ) { - PIE.OnUnload.attachManagedEvent( window, 'onbeforeprint', beforePrint ); - PIE.OnUnload.attachManagedEvent( window, 'onafterprint', afterPrint ); - } - -})();/** - * Create a single observable listener for document mouseup events. - */ -PIE.OnMouseup = new PIE.Observable(); - -PIE.OnUnload.attachManagedEvent( doc, 'onmouseup', function() { PIE.OnMouseup.fire(); } ); -/** - * Wrapper for length and percentage style values. The value is immutable. A singleton instance per unique - * value is returned from PIE.getLength() - always use that instead of instantiating directly. - * @constructor - * @param {string} val The CSS string representing the length. It is assumed that this will already have - * been validated as a valid length or percentage syntax. - */ -PIE.Length = (function() { - var lengthCalcEl = doc.createElement( 'length-calc' ), - parent = doc.body || doc.documentElement, - s = lengthCalcEl.style, - conversions = {}, - units = [ 'mm', 'cm', 'in', 'pt', 'pc' ], - i = units.length, - instances = {}; - - s.position = 'absolute'; - s.top = s.left = '-9999px'; - - parent.appendChild( lengthCalcEl ); - while( i-- ) { - s.width = '100' + units[i]; - conversions[ units[i] ] = lengthCalcEl.offsetWidth / 100; - } - parent.removeChild( lengthCalcEl ); - - // All calcs from here on will use 1em - s.width = '1em'; - - - function Length( val ) { - this.val = val; - } - Length.prototype = { - /** - * Regular expression for matching the length unit - * @private - */ - unitRE: /(px|em|ex|mm|cm|in|pt|pc|%)$/, - - /** - * Get the numeric value of the length - * @return {number} The value - */ - getNumber: function() { - var num = this.num, - UNDEF; - if( num === UNDEF ) { - num = this.num = parseFloat( this.val ); - } - return num; - }, - - /** - * Get the unit of the length - * @return {string} The unit - */ - getUnit: function() { - var unit = this.unit, - m; - if( !unit ) { - m = this.val.match( this.unitRE ); - unit = this.unit = ( m && m[0] ) || 'px'; - } - return unit; - }, - - /** - * Determine whether this is a percentage length value - * @return {boolean} - */ - isPercentage: function() { - return this.getUnit() === '%'; - }, - - /** - * Resolve this length into a number of pixels. - * @param {Element} el - the context element, used to resolve font-relative values - * @param {(function():number|number)=} pct100 - the number of pixels that equal a 100% percentage. This can be either a number or a - * function which will be called to return the number. - */ - pixels: function( el, pct100 ) { - var num = this.getNumber(), - unit = this.getUnit(); - switch( unit ) { - case "px": - return num; - case "%": - return num * ( typeof pct100 === 'function' ? pct100() : pct100 ) / 100; - case "em": - return num * this.getEmPixels( el ); - case "ex": - return num * this.getEmPixels( el ) / 2; - default: - return num * conversions[ unit ]; - } - }, - - /** - * The em and ex units are relative to the font-size of the current element, - * however if the font-size is set using non-pixel units then we get that value - * rather than a pixel conversion. To get around this, we keep a floating element - * with width:1em which we insert into the target element and then read its offsetWidth. - * For elements that won't accept a child we insert into the parent node and perform - * additional calculation. If the font-size *is* specified in pixels, then we use that - * directly to avoid the expensive DOM manipulation. - * @param {Element} el - * @return {number} - */ - getEmPixels: function( el ) { - var fs = el.currentStyle.fontSize, - px, parent, me; - - if( fs.indexOf( 'px' ) > 0 ) { - return parseFloat( fs ); - } - else if( el.tagName in PIE.childlessElements ) { - me = this; - parent = el.parentNode; - return PIE.getLength( fs ).pixels( parent, function() { - return me.getEmPixels( parent ); - } ); - } - else { - el.appendChild( lengthCalcEl ); - px = lengthCalcEl.offsetWidth; - if( lengthCalcEl.parentNode === el ) { //not sure how this could be false but it sometimes is - el.removeChild( lengthCalcEl ); - } - return px; - } - } - }; - - - /** - * Retrieve a PIE.Length instance for the given value. A shared singleton instance is returned for each unique value. - * @param {string} val The CSS string representing the length. It is assumed that this will already have - * been validated as a valid length or percentage syntax. - */ - PIE.getLength = function( val ) { - return instances[ val ] || ( instances[ val ] = new Length( val ) ); - }; - - return Length; -})(); -/** - * Wrapper for a CSS3 bg-position value. Takes up to 2 position keywords and 2 lengths/percentages. - * @constructor - * @param {Array.} tokens The tokens making up the background position value. - */ -PIE.BgPosition = (function() { - - var length_fifty = PIE.getLength( '50%' ), - vert_idents = { 'top': 1, 'center': 1, 'bottom': 1 }, - horiz_idents = { 'left': 1, 'center': 1, 'right': 1 }; - - - function BgPosition( tokens ) { - this.tokens = tokens; - } - BgPosition.prototype = { - /** - * Normalize the values into the form: - * [ xOffsetSide, xOffsetLength, yOffsetSide, yOffsetLength ] - * where: xOffsetSide is either 'left' or 'right', - * yOffsetSide is either 'top' or 'bottom', - * and x/yOffsetLength are both PIE.Length objects. - * @return {Array} - */ - getValues: function() { - if( !this._values ) { - var tokens = this.tokens, - len = tokens.length, - Tokenizer = PIE.Tokenizer, - identType = Tokenizer.Type, - length_zero = PIE.getLength( '0' ), - type_ident = identType.IDENT, - type_length = identType.LENGTH, - type_percent = identType.PERCENT, - type, value, - vals = [ 'left', length_zero, 'top', length_zero ]; - - // If only one value, the second is assumed to be 'center' - if( len === 1 ) { - tokens.push( new Tokenizer.Token( type_ident, 'center' ) ); - len++; - } - - // Two values - CSS2 - if( len === 2 ) { - // If both idents, they can appear in either order, so switch them if needed - if( type_ident & ( tokens[0].tokenType | tokens[1].tokenType ) && - tokens[0].tokenValue in vert_idents && tokens[1].tokenValue in horiz_idents ) { - tokens.push( tokens.shift() ); - } - if( tokens[0].tokenType & type_ident ) { - if( tokens[0].tokenValue === 'center' ) { - vals[1] = length_fifty; - } else { - vals[0] = tokens[0].tokenValue; - } - } - else if( tokens[0].isLengthOrPercent() ) { - vals[1] = PIE.getLength( tokens[0].tokenValue ); - } - if( tokens[1].tokenType & type_ident ) { - if( tokens[1].tokenValue === 'center' ) { - vals[3] = length_fifty; - } else { - vals[2] = tokens[1].tokenValue; - } - } - else if( tokens[1].isLengthOrPercent() ) { - vals[3] = PIE.getLength( tokens[1].tokenValue ); - } - } - - // Three or four values - CSS3 - else { - // TODO - } - - this._values = vals; - } - return this._values; - }, - - /** - * Find the coordinates of the background image from the upper-left corner of the background area. - * Note that these coordinate values are not rounded. - * @param {Element} el - * @param {number} width - the width for percentages (background area width minus image width) - * @param {number} height - the height for percentages (background area height minus image height) - * @return {Object} { x: Number, y: Number } - */ - coords: function( el, width, height ) { - var vals = this.getValues(), - pxX = vals[1].pixels( el, width ), - pxY = vals[3].pixels( el, height ); - - return { - x: vals[0] === 'right' ? width - pxX : pxX, - y: vals[2] === 'bottom' ? height - pxY : pxY - }; - } - }; - - return BgPosition; -})(); -/** - * Wrapper for a CSS3 background-size value. - * @constructor - * @param {String|PIE.Length} w The width parameter - * @param {String|PIE.Length} h The height parameter, if any - */ -PIE.BgSize = (function() { - - var CONTAIN = 'contain', - COVER = 'cover', - AUTO = 'auto'; - - - function BgSize( w, h ) { - this.w = w; - this.h = h; - } - BgSize.prototype = { - - pixels: function( el, areaW, areaH, imgW, imgH ) { - var me = this, - w = me.w, - h = me.h, - areaRatio = areaW / areaH, - imgRatio = imgW / imgH; - - if ( w === CONTAIN ) { - w = imgRatio > areaRatio ? areaW : areaH * imgRatio; - h = imgRatio > areaRatio ? areaW / imgRatio : areaH; - } - else if ( w === COVER ) { - w = imgRatio < areaRatio ? areaW : areaH * imgRatio; - h = imgRatio < areaRatio ? areaW / imgRatio : areaH; - } - else if ( w === AUTO ) { - h = ( h === AUTO ? imgH : h.pixels( el, areaH ) ); - w = h * imgRatio; - } - else { - w = w.pixels( el, areaW ); - h = ( h === AUTO ? w / imgRatio : h.pixels( el, areaH ) ); - } - - return { w: w, h: h }; - } - - }; - - BgSize.DEFAULT = new BgSize( AUTO, AUTO ); - - return BgSize; -})(); -/** - * Wrapper for angle values; handles conversion to degrees from all allowed angle units - * @constructor - * @param {string} val The raw CSS value for the angle. It is assumed it has been pre-validated. - */ -PIE.Angle = (function() { - function Angle( val ) { - this.val = val; - } - Angle.prototype = { - unitRE: /[a-z]+$/i, - - /** - * @return {string} The unit of the angle value - */ - getUnit: function() { - return this._unit || ( this._unit = this.val.match( this.unitRE )[0].toLowerCase() ); - }, - - /** - * Get the numeric value of the angle in degrees. - * @return {number} The degrees value - */ - degrees: function() { - var deg = this._deg, u, n; - if( deg === undefined ) { - u = this.getUnit(); - n = parseFloat( this.val, 10 ); - deg = this._deg = ( u === 'deg' ? n : u === 'rad' ? n / Math.PI * 180 : u === 'grad' ? n / 400 * 360 : u === 'turn' ? n * 360 : 0 ); - } - return deg; - } - }; - - return Angle; -})();/** - * Abstraction for colors values. Allows detection of rgba values. A singleton instance per unique - * value is returned from PIE.getColor() - always use that instead of instantiating directly. - * @constructor - * @param {string} val The raw CSS string value for the color - */ -PIE.Color = (function() { - var instances = {}; - - function Color( val ) { - this.val = val; - } - - /** - * Regular expression for matching rgba colors and extracting their components - * @type {RegExp} - */ - Color.rgbaRE = /\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/; - - Color.names = { - "aliceblue":"F0F8FF", "antiquewhite":"FAEBD7", "aqua":"0FF", - "aquamarine":"7FFFD4", "azure":"F0FFFF", "beige":"F5F5DC", - "bisque":"FFE4C4", "black":"000", "blanchedalmond":"FFEBCD", - "blue":"00F", "blueviolet":"8A2BE2", "brown":"A52A2A", - "burlywood":"DEB887", "cadetblue":"5F9EA0", "chartreuse":"7FFF00", - "chocolate":"D2691E", "coral":"FF7F50", "cornflowerblue":"6495ED", - "cornsilk":"FFF8DC", "crimson":"DC143C", "cyan":"0FF", - "darkblue":"00008B", "darkcyan":"008B8B", "darkgoldenrod":"B8860B", - "darkgray":"A9A9A9", "darkgreen":"006400", "darkkhaki":"BDB76B", - "darkmagenta":"8B008B", "darkolivegreen":"556B2F", "darkorange":"FF8C00", - "darkorchid":"9932CC", "darkred":"8B0000", "darksalmon":"E9967A", - "darkseagreen":"8FBC8F", "darkslateblue":"483D8B", "darkslategray":"2F4F4F", - "darkturquoise":"00CED1", "darkviolet":"9400D3", "deeppink":"FF1493", - "deepskyblue":"00BFFF", "dimgray":"696969", "dodgerblue":"1E90FF", - "firebrick":"B22222", "floralwhite":"FFFAF0", "forestgreen":"228B22", - "fuchsia":"F0F", "gainsboro":"DCDCDC", "ghostwhite":"F8F8FF", - "gold":"FFD700", "goldenrod":"DAA520", "gray":"808080", - "green":"008000", "greenyellow":"ADFF2F", "honeydew":"F0FFF0", - "hotpink":"FF69B4", "indianred":"CD5C5C", "indigo":"4B0082", - "ivory":"FFFFF0", "khaki":"F0E68C", "lavender":"E6E6FA", - "lavenderblush":"FFF0F5", "lawngreen":"7CFC00", "lemonchiffon":"FFFACD", - "lightblue":"ADD8E6", "lightcoral":"F08080", "lightcyan":"E0FFFF", - "lightgoldenrodyellow":"FAFAD2", "lightgreen":"90EE90", "lightgrey":"D3D3D3", - "lightpink":"FFB6C1", "lightsalmon":"FFA07A", "lightseagreen":"20B2AA", - "lightskyblue":"87CEFA", "lightslategray":"789", "lightsteelblue":"B0C4DE", - "lightyellow":"FFFFE0", "lime":"0F0", "limegreen":"32CD32", - "linen":"FAF0E6", "magenta":"F0F", "maroon":"800000", - "mediumauqamarine":"66CDAA", "mediumblue":"0000CD", "mediumorchid":"BA55D3", - "mediumpurple":"9370D8", "mediumseagreen":"3CB371", "mediumslateblue":"7B68EE", - "mediumspringgreen":"00FA9A", "mediumturquoise":"48D1CC", "mediumvioletred":"C71585", - "midnightblue":"191970", "mintcream":"F5FFFA", "mistyrose":"FFE4E1", - "moccasin":"FFE4B5", "navajowhite":"FFDEAD", "navy":"000080", - "oldlace":"FDF5E6", "olive":"808000", "olivedrab":"688E23", - "orange":"FFA500", "orangered":"FF4500", "orchid":"DA70D6", - "palegoldenrod":"EEE8AA", "palegreen":"98FB98", "paleturquoise":"AFEEEE", - "palevioletred":"D87093", "papayawhip":"FFEFD5", "peachpuff":"FFDAB9", - "peru":"CD853F", "pink":"FFC0CB", "plum":"DDA0DD", - "powderblue":"B0E0E6", "purple":"800080", "red":"F00", - "rosybrown":"BC8F8F", "royalblue":"4169E1", "saddlebrown":"8B4513", - "salmon":"FA8072", "sandybrown":"F4A460", "seagreen":"2E8B57", - "seashell":"FFF5EE", "sienna":"A0522D", "silver":"C0C0C0", - "skyblue":"87CEEB", "slateblue":"6A5ACD", "slategray":"708090", - "snow":"FFFAFA", "springgreen":"00FF7F", "steelblue":"4682B4", - "tan":"D2B48C", "teal":"008080", "thistle":"D8BFD8", - "tomato":"FF6347", "turquoise":"40E0D0", "violet":"EE82EE", - "wheat":"F5DEB3", "white":"FFF", "whitesmoke":"F5F5F5", - "yellow":"FF0", "yellowgreen":"9ACD32" - }; - - Color.prototype = { - /** - * @private - */ - parse: function() { - if( !this._color ) { - var me = this, - v = me.val, - vLower, - m = v.match( Color.rgbaRE ); - if( m ) { - me._color = 'rgb(' + m[1] + ',' + m[2] + ',' + m[3] + ')'; - me._alpha = parseFloat( m[4] ); - } - else { - if( ( vLower = v.toLowerCase() ) in Color.names ) { - v = '#' + Color.names[vLower]; - } - me._color = v; - me._alpha = ( v === 'transparent' ? 0 : 1 ); - } - } - }, - - /** - * Retrieve the value of the color in a format usable by IE natively. This will be the same as - * the raw input value, except for rgba values which will be converted to an rgb value. - * @param {Element} el The context element, used to get 'currentColor' keyword value. - * @return {string} Color value - */ - colorValue: function( el ) { - this.parse(); - return this._color === 'currentColor' ? el.currentStyle.color : this._color; - }, - - /** - * Retrieve the alpha value of the color. Will be 1 for all values except for rgba values - * with an alpha component. - * @return {number} The alpha value, from 0 to 1. - */ - alpha: function() { - this.parse(); - return this._alpha; - } - }; - - - /** - * Retrieve a PIE.Color instance for the given value. A shared singleton instance is returned for each unique value. - * @param {string} val The CSS string representing the color. It is assumed that this will already have - * been validated as a valid color syntax. - */ - PIE.getColor = function(val) { - return instances[ val ] || ( instances[ val ] = new Color( val ) ); - }; - - return Color; -})();/** - * A tokenizer for CSS value strings. - * @constructor - * @param {string} css The CSS value string - */ -PIE.Tokenizer = (function() { - function Tokenizer( css ) { - this.css = css; - this.ch = 0; - this.tokens = []; - this.tokenIndex = 0; - } - - /** - * Enumeration of token type constants. - * @enum {number} - */ - var Type = Tokenizer.Type = { - ANGLE: 1, - CHARACTER: 2, - COLOR: 4, - DIMEN: 8, - FUNCTION: 16, - IDENT: 32, - LENGTH: 64, - NUMBER: 128, - OPERATOR: 256, - PERCENT: 512, - STRING: 1024, - URL: 2048 - }; - - /** - * A single token - * @constructor - * @param {number} type The type of the token - see PIE.Tokenizer.Type - * @param {string} value The value of the token - */ - Tokenizer.Token = function( type, value ) { - this.tokenType = type; - this.tokenValue = value; - }; - Tokenizer.Token.prototype = { - isLength: function() { - return this.tokenType & Type.LENGTH || ( this.tokenType & Type.NUMBER && this.tokenValue === '0' ); - }, - isLengthOrPercent: function() { - return this.isLength() || this.tokenType & Type.PERCENT; - } - }; - - Tokenizer.prototype = { - whitespace: /\s/, - number: /^[\+\-]?(\d*\.)?\d+/, - url: /^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i, - ident: /^\-?[_a-z][\w-]*/i, - string: /^("([^"]*)"|'([^']*)')/, - operator: /^[\/,]/, - hash: /^#[\w]+/, - hashColor: /^#([\da-f]{6}|[\da-f]{3})/i, - - unitTypes: { - 'px': Type.LENGTH, 'em': Type.LENGTH, 'ex': Type.LENGTH, - 'mm': Type.LENGTH, 'cm': Type.LENGTH, 'in': Type.LENGTH, - 'pt': Type.LENGTH, 'pc': Type.LENGTH, - 'deg': Type.ANGLE, 'rad': Type.ANGLE, 'grad': Type.ANGLE - }, - - colorFunctions: { - 'rgb': 1, 'rgba': 1, 'hsl': 1, 'hsla': 1 - }, - - - /** - * Advance to and return the next token in the CSS string. If the end of the CSS string has - * been reached, null will be returned. - * @param {boolean} forget - if true, the token will not be stored for the purposes of backtracking with prev(). - * @return {PIE.Tokenizer.Token} - */ - next: function( forget ) { - var css, ch, firstChar, match, val, - me = this; - - function newToken( type, value ) { - var tok = new Tokenizer.Token( type, value ); - if( !forget ) { - me.tokens.push( tok ); - me.tokenIndex++; - } - return tok; - } - function failure() { - me.tokenIndex++; - return null; - } - - // In case we previously backed up, return the stored token in the next slot - if( this.tokenIndex < this.tokens.length ) { - return this.tokens[ this.tokenIndex++ ]; - } - - // Move past leading whitespace characters - while( this.whitespace.test( this.css.charAt( this.ch ) ) ) { - this.ch++; - } - if( this.ch >= this.css.length ) { - return failure(); - } - - ch = this.ch; - css = this.css.substring( this.ch ); - firstChar = css.charAt( 0 ); - switch( firstChar ) { - case '#': - if( match = css.match( this.hashColor ) ) { - this.ch += match[0].length; - return newToken( Type.COLOR, match[0] ); - } - break; - - case '"': - case "'": - if( match = css.match( this.string ) ) { - this.ch += match[0].length; - return newToken( Type.STRING, match[2] || match[3] || '' ); - } - break; - - case "/": - case ",": - this.ch++; - return newToken( Type.OPERATOR, firstChar ); - - case 'u': - if( match = css.match( this.url ) ) { - this.ch += match[0].length; - return newToken( Type.URL, match[2] || match[3] || match[4] || '' ); - } - } - - // Numbers and values starting with numbers - if( match = css.match( this.number ) ) { - val = match[0]; - this.ch += val.length; - - // Check if it is followed by a unit - if( css.charAt( val.length ) === '%' ) { - this.ch++; - return newToken( Type.PERCENT, val + '%' ); - } - if( match = css.substring( val.length ).match( this.ident ) ) { - val += match[0]; - this.ch += match[0].length; - return newToken( this.unitTypes[ match[0].toLowerCase() ] || Type.DIMEN, val ); - } - - // Plain ol' number - return newToken( Type.NUMBER, val ); - } - - // Identifiers - if( match = css.match( this.ident ) ) { - val = match[0]; - this.ch += val.length; - - // Named colors - if( val.toLowerCase() in PIE.Color.names || val === 'currentColor' || val === 'transparent' ) { - return newToken( Type.COLOR, val ); - } - - // Functions - if( css.charAt( val.length ) === '(' ) { - this.ch++; - - // Color values in function format: rgb, rgba, hsl, hsla - if( val.toLowerCase() in this.colorFunctions ) { - function isNum( tok ) { - return tok && tok.tokenType & Type.NUMBER; - } - function isNumOrPct( tok ) { - return tok && ( tok.tokenType & ( Type.NUMBER | Type.PERCENT ) ); - } - function isValue( tok, val ) { - return tok && tok.tokenValue === val; - } - function next() { - return me.next( 1 ); - } - - if( ( val.charAt(0) === 'r' ? isNumOrPct( next() ) : isNum( next() ) ) && - isValue( next(), ',' ) && - isNumOrPct( next() ) && - isValue( next(), ',' ) && - isNumOrPct( next() ) && - ( val === 'rgb' || val === 'hsa' || ( - isValue( next(), ',' ) && - isNum( next() ) - ) ) && - isValue( next(), ')' ) ) { - return newToken( Type.COLOR, this.css.substring( ch, this.ch ) ); - } - return failure(); - } - - return newToken( Type.FUNCTION, val ); - } - - // Other identifier - return newToken( Type.IDENT, val ); - } - - // Standalone character - this.ch++; - return newToken( Type.CHARACTER, firstChar ); - }, - - /** - * Determine whether there is another token - * @return {boolean} - */ - hasNext: function() { - var next = this.next(); - this.prev(); - return !!next; - }, - - /** - * Back up and return the previous token - * @return {PIE.Tokenizer.Token} - */ - prev: function() { - return this.tokens[ this.tokenIndex-- - 2 ]; - }, - - /** - * Retrieve all the tokens in the CSS string - * @return {Array.} - */ - all: function() { - while( this.next() ) {} - return this.tokens; - }, - - /** - * Return a list of tokens from the current position until the given function returns - * true. The final token will not be included in the list. - * @param {function():boolean} func - test function - * @param {boolean} require - if true, then if the end of the CSS string is reached - * before the test function returns true, null will be returned instead of the - * tokens that have been found so far. - * @return {Array.} - */ - until: function( func, require ) { - var list = [], t, hit; - while( t = this.next() ) { - if( func( t ) ) { - hit = true; - this.prev(); - break; - } - list.push( t ); - } - return require && !hit ? null : list; - } - }; - - return Tokenizer; -})();/** - * Handles calculating, caching, and detecting changes to size and position of the element. - * @constructor - * @param {Element} el the target element - */ -PIE.BoundsInfo = function( el ) { - this.targetElement = el; -}; -PIE.BoundsInfo.prototype = { - - _locked: 0, - - positionChanged: function() { - var last = this._lastBounds, - bounds; - return !last || ( ( bounds = this.getBounds() ) && ( last.x !== bounds.x || last.y !== bounds.y ) ); - }, - - sizeChanged: function() { - var last = this._lastBounds, - bounds; - return !last || ( ( bounds = this.getBounds() ) && ( last.w !== bounds.w || last.h !== bounds.h ) ); - }, - - getLiveBounds: function() { - var el = this.targetElement, - rect = el.getBoundingClientRect(), - isIE9 = PIE.ieDocMode === 9, - isIE7 = PIE.ieVersion === 7, - width = rect.right - rect.left; - return { - x: rect.left, - y: rect.top, - // In some cases scrolling the page will cause IE9 to report incorrect dimensions - // in the rect returned by getBoundingClientRect, so we must query offsetWidth/Height - // instead. Also IE7 is inconsistent in using logical vs. device pixels in measurements - // so we must calculate the ratio and use it in certain places as a position adjustment. - w: isIE9 || isIE7 ? el.offsetWidth : width, - h: isIE9 || isIE7 ? el.offsetHeight : rect.bottom - rect.top, - logicalZoomRatio: ( isIE7 && width ) ? el.offsetWidth / width : 1 - }; - }, - - getBounds: function() { - return this._locked ? - ( this._lockedBounds || ( this._lockedBounds = this.getLiveBounds() ) ) : - this.getLiveBounds(); - }, - - hasBeenQueried: function() { - return !!this._lastBounds; - }, - - lock: function() { - ++this._locked; - }, - - unlock: function() { - if( !--this._locked ) { - if( this._lockedBounds ) this._lastBounds = this._lockedBounds; - this._lockedBounds = null; - } - } - -}; -(function() { - -function cacheWhenLocked( fn ) { - var uid = PIE.Util.getUID( fn ); - return function() { - if( this._locked ) { - var cache = this._lockedValues || ( this._lockedValues = {} ); - return ( uid in cache ) ? cache[ uid ] : ( cache[ uid ] = fn.call( this ) ); - } else { - return fn.call( this ); - } - } -} - - -PIE.StyleInfoBase = { - - _locked: 0, - - /** - * Create a new StyleInfo class, with the standard constructor, and augmented by - * the StyleInfoBase's members. - * @param proto - */ - newStyleInfo: function( proto ) { - function StyleInfo( el ) { - this.targetElement = el; - this._lastCss = this.getCss(); - } - PIE.Util.merge( StyleInfo.prototype, PIE.StyleInfoBase, proto ); - StyleInfo._propsCache = {}; - return StyleInfo; - }, - - /** - * Get an object representation of the target CSS style, caching it for each unique - * CSS value string. - * @return {Object} - */ - getProps: function() { - var css = this.getCss(), - cache = this.constructor._propsCache; - return css ? ( css in cache ? cache[ css ] : ( cache[ css ] = this.parseCss( css ) ) ) : null; - }, - - /** - * Get the raw CSS value for the target style - * @return {string} - */ - getCss: cacheWhenLocked( function() { - var el = this.targetElement, - ctor = this.constructor, - s = el.style, - cs = el.currentStyle, - cssProp = this.cssProperty, - styleProp = this.styleProperty, - prefixedCssProp = ctor._prefixedCssProp || ( ctor._prefixedCssProp = PIE.CSS_PREFIX + cssProp ), - prefixedStyleProp = ctor._prefixedStyleProp || ( ctor._prefixedStyleProp = PIE.STYLE_PREFIX + styleProp.charAt(0).toUpperCase() + styleProp.substring(1) ); - return s[ prefixedStyleProp ] || cs.getAttribute( prefixedCssProp ) || s[ styleProp ] || cs.getAttribute( cssProp ); - } ), - - /** - * Determine whether the target CSS style is active. - * @return {boolean} - */ - isActive: cacheWhenLocked( function() { - return !!this.getProps(); - } ), - - /** - * Determine whether the target CSS style has changed since the last time it was used. - * @return {boolean} - */ - changed: cacheWhenLocked( function() { - var currentCss = this.getCss(), - changed = currentCss !== this._lastCss; - this._lastCss = currentCss; - return changed; - } ), - - cacheWhenLocked: cacheWhenLocked, - - lock: function() { - ++this._locked; - }, - - unlock: function() { - if( !--this._locked ) { - delete this._lockedValues; - } - } -}; - -})();/** - * Handles parsing, caching, and detecting changes to background (and -pie-background) CSS - * @constructor - * @param {Element} el the target element - */ -PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - cssProperty: PIE.CSS_PREFIX + 'background', - styleProperty: PIE.STYLE_PREFIX + 'Background', - - attachIdents: { 'scroll':1, 'fixed':1, 'local':1 }, - repeatIdents: { 'repeat-x':1, 'repeat-y':1, 'repeat':1, 'no-repeat':1 }, - originAndClipIdents: { 'padding-box':1, 'border-box':1, 'content-box':1 }, - positionIdents: { 'top':1, 'right':1, 'bottom':1, 'left':1, 'center':1 }, - sizeIdents: { 'contain':1, 'cover':1 }, - propertyNames: { - CLIP: 'backgroundClip', - COLOR: 'backgroundColor', - IMAGE: 'backgroundImage', - ORIGIN: 'backgroundOrigin', - POSITION: 'backgroundPosition', - REPEAT: 'backgroundRepeat', - SIZE: 'backgroundSize' - }, - - /** - * For background styles, we support the -pie-background property but fall back to the standard - * backround* properties. The reason we have to use the prefixed version is that IE natively - * parses the standard properties and if it sees something it doesn't know how to parse, for example - * multiple values or gradient definitions, it will throw that away and not make it available through - * currentStyle. - * - * Format of return object: - * { - * color: , - * bgImages: [ - * { - * imgType: 'image', - * imgUrl: 'image.png', - * imgRepeat: <'no-repeat' | 'repeat-x' | 'repeat-y' | 'repeat'>, - * bgPosition: , - * bgAttachment: <'scroll' | 'fixed' | 'local'>, - * bgOrigin: <'border-box' | 'padding-box' | 'content-box'>, - * bgClip: <'border-box' | 'padding-box'>, - * bgSize: , - * origString: 'url(img.png) no-repeat top left' - * }, - * { - * imgType: 'linear-gradient', - * gradientStart: , - * angle: , - * stops: [ - * { color: , offset: }, - * { color: , offset: }, ... - * ] - * } - * ] - * } - * @param {String} css - * @override - */ - parseCss: function( css ) { - var el = this.targetElement, - cs = el.currentStyle, - tokenizer, token, image, - tok_type = PIE.Tokenizer.Type, - type_operator = tok_type.OPERATOR, - type_ident = tok_type.IDENT, - type_color = tok_type.COLOR, - tokType, tokVal, - beginCharIndex = 0, - positionIdents = this.positionIdents, - gradient, stop, width, height, - props = { bgImages: [] }; - - function isBgPosToken( token ) { - return token && token.isLengthOrPercent() || ( token.tokenType & type_ident && token.tokenValue in positionIdents ); - } - - function sizeToken( token ) { - return token && ( ( token.isLengthOrPercent() && PIE.getLength( token.tokenValue ) ) || ( token.tokenValue === 'auto' && 'auto' ) ); - } - - // If the CSS3-specific -pie-background property is present, parse it - if( this.getCss3() ) { - tokenizer = new PIE.Tokenizer( css ); - image = {}; - - while( token = tokenizer.next() ) { - tokType = token.tokenType; - tokVal = token.tokenValue; - - if( !image.imgType && tokType & tok_type.FUNCTION && tokVal === 'linear-gradient' ) { - gradient = { stops: [], imgType: tokVal }; - stop = {}; - while( token = tokenizer.next() ) { - tokType = token.tokenType; - tokVal = token.tokenValue; - - // If we reached the end of the function and had at least 2 stops, flush the info - if( tokType & tok_type.CHARACTER && tokVal === ')' ) { - if( stop.color ) { - gradient.stops.push( stop ); - } - if( gradient.stops.length > 1 ) { - PIE.Util.merge( image, gradient ); - } - break; - } - - // Color stop - must start with color - if( tokType & type_color ) { - // if we already have an angle/position, make sure that the previous token was a comma - if( gradient.angle || gradient.gradientStart ) { - token = tokenizer.prev(); - if( token.tokenType !== type_operator ) { - break; //fail - } - tokenizer.next(); - } - - stop = { - color: PIE.getColor( tokVal ) - }; - // check for offset following color - token = tokenizer.next(); - if( token.isLengthOrPercent() ) { - stop.offset = PIE.getLength( token.tokenValue ); - } else { - tokenizer.prev(); - } - } - // Angle - can only appear in first spot - else if( tokType & tok_type.ANGLE && !gradient.angle && !stop.color && !gradient.stops.length ) { - gradient.angle = new PIE.Angle( token.tokenValue ); - } - else if( isBgPosToken( token ) && !gradient.gradientStart && !stop.color && !gradient.stops.length ) { - tokenizer.prev(); - gradient.gradientStart = new PIE.BgPosition( - tokenizer.until( function( t ) { - return !isBgPosToken( t ); - }, false ) - ); - } - else if( tokType & type_operator && tokVal === ',' ) { - if( stop.color ) { - gradient.stops.push( stop ); - stop = {}; - } - } - else { - // Found something we didn't recognize; fail without adding image - break; - } - } - } - else if( !image.imgType && tokType & tok_type.URL ) { - image.imgUrl = tokVal; - image.imgType = 'image'; - } - else if( isBgPosToken( token ) && !image.bgPosition ) { - tokenizer.prev(); - image.bgPosition = new PIE.BgPosition( - tokenizer.until( function( t ) { - return !isBgPosToken( t ); - }, false ) - ); - } - else if( tokType & type_ident ) { - if( tokVal in this.repeatIdents && !image.imgRepeat ) { - image.imgRepeat = tokVal; - } - else if( tokVal in this.originAndClipIdents && !image.bgOrigin ) { - image.bgOrigin = tokVal; - if( ( token = tokenizer.next() ) && ( token.tokenType & type_ident ) && - token.tokenValue in this.originAndClipIdents ) { - image.bgClip = token.tokenValue; - } else { - image.bgClip = tokVal; - tokenizer.prev(); - } - } - else if( tokVal in this.attachIdents && !image.bgAttachment ) { - image.bgAttachment = tokVal; - } - else { - return null; - } - } - else if( tokType & type_color && !props.color ) { - props.color = PIE.getColor( tokVal ); - } - else if( tokType & type_operator && tokVal === '/' && !image.bgSize && image.bgPosition ) { - // background size - token = tokenizer.next(); - if( token.tokenType & type_ident && token.tokenValue in this.sizeIdents ) { - image.bgSize = new PIE.BgSize( token.tokenValue ); - } - else if( width = sizeToken( token ) ) { - height = sizeToken( tokenizer.next() ); - if ( !height ) { - height = width; - tokenizer.prev(); - } - image.bgSize = new PIE.BgSize( width, height ); - } - else { - return null; - } - } - // new layer - else if( tokType & type_operator && tokVal === ',' && image.imgType ) { - image.origString = css.substring( beginCharIndex, tokenizer.ch - 1 ); - beginCharIndex = tokenizer.ch; - props.bgImages.push( image ); - image = {}; - } - else { - // Found something unrecognized; chuck everything - return null; - } - } - - // leftovers - if( image.imgType ) { - image.origString = css.substring( beginCharIndex ); - props.bgImages.push( image ); - } - } - - // Otherwise, use the standard background properties; let IE give us the values rather than parsing them - else { - this.withActualBg( PIE.ieDocMode < 9 ? - function() { - var propNames = this.propertyNames, - posX = cs[propNames.POSITION + 'X'], - posY = cs[propNames.POSITION + 'Y'], - img = cs[propNames.IMAGE], - color = cs[propNames.COLOR]; - - if( color !== 'transparent' ) { - props.color = PIE.getColor( color ) - } - if( img !== 'none' ) { - props.bgImages = [ { - imgType: 'image', - imgUrl: new PIE.Tokenizer( img ).next().tokenValue, - imgRepeat: cs[propNames.REPEAT], - bgPosition: new PIE.BgPosition( new PIE.Tokenizer( posX + ' ' + posY ).all() ) - } ]; - } - } : - function() { - var propNames = this.propertyNames, - splitter = /\s*,\s*/, - images = cs[propNames.IMAGE].split( splitter ), - color = cs[propNames.COLOR], - repeats, positions, origins, clips, sizes, i, len, image, sizeParts; - - if( color !== 'transparent' ) { - props.color = PIE.getColor( color ) - } - - len = images.length; - if( len && images[0] !== 'none' ) { - repeats = cs[propNames.REPEAT].split( splitter ); - positions = cs[propNames.POSITION].split( splitter ); - origins = cs[propNames.ORIGIN].split( splitter ); - clips = cs[propNames.CLIP].split( splitter ); - sizes = cs[propNames.SIZE].split( splitter ); - - props.bgImages = []; - for( i = 0; i < len; i++ ) { - image = images[ i ]; - if( image && image !== 'none' ) { - sizeParts = sizes[i].split( ' ' ); - props.bgImages.push( { - origString: image + ' ' + repeats[ i ] + ' ' + positions[ i ] + ' / ' + sizes[ i ] + ' ' + - origins[ i ] + ' ' + clips[ i ], - imgType: 'image', - imgUrl: new PIE.Tokenizer( image ).next().tokenValue, - imgRepeat: repeats[ i ], - bgPosition: new PIE.BgPosition( new PIE.Tokenizer( positions[ i ] ).all() ), - bgOrigin: origins[ i ], - bgClip: clips[ i ], - bgSize: new PIE.BgSize( sizeParts[ 0 ], sizeParts[ 1 ] ) - } ); - } - } - } - } - ); - } - - return ( props.color || props.bgImages[0] ) ? props : null; - }, - - /** - * Execute a function with the actual background styles (not overridden with runtimeStyle - * properties set by the renderers) available via currentStyle. - * @param fn - */ - withActualBg: function( fn ) { - var isIE9 = PIE.ieDocMode > 8, - propNames = this.propertyNames, - rs = this.targetElement.runtimeStyle, - rsImage = rs[propNames.IMAGE], - rsColor = rs[propNames.COLOR], - rsRepeat = rs[propNames.REPEAT], - rsClip, rsOrigin, rsSize, rsPosition, ret; - - if( rsImage ) rs[propNames.IMAGE] = ''; - if( rsColor ) rs[propNames.COLOR] = ''; - if( rsRepeat ) rs[propNames.REPEAT] = ''; - if( isIE9 ) { - rsClip = rs[propNames.CLIP]; - rsOrigin = rs[propNames.ORIGIN]; - rsPosition = rs[propNames.POSITION]; - rsSize = rs[propNames.SIZE]; - if( rsClip ) rs[propNames.CLIP] = ''; - if( rsOrigin ) rs[propNames.ORIGIN] = ''; - if( rsPosition ) rs[propNames.POSITION] = ''; - if( rsSize ) rs[propNames.SIZE] = ''; - } - - ret = fn.call( this ); - - if( rsImage ) rs[propNames.IMAGE] = rsImage; - if( rsColor ) rs[propNames.COLOR] = rsColor; - if( rsRepeat ) rs[propNames.REPEAT] = rsRepeat; - if( isIE9 ) { - if( rsClip ) rs[propNames.CLIP] = rsClip; - if( rsOrigin ) rs[propNames.ORIGIN] = rsOrigin; - if( rsPosition ) rs[propNames.POSITION] = rsPosition; - if( rsSize ) rs[propNames.SIZE] = rsSize; - } - - return ret; - }, - - getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { - return this.getCss3() || - this.withActualBg( function() { - var cs = this.targetElement.currentStyle, - propNames = this.propertyNames; - return cs[propNames.COLOR] + ' ' + cs[propNames.IMAGE] + ' ' + cs[propNames.REPEAT] + ' ' + - cs[propNames.POSITION + 'X'] + ' ' + cs[propNames.POSITION + 'Y']; - } ); - } ), - - getCss3: PIE.StyleInfoBase.cacheWhenLocked( function() { - var el = this.targetElement; - return el.style[ this.styleProperty ] || el.currentStyle.getAttribute( this.cssProperty ); - } ), - - /** - * Tests if style.PiePngFix or the -pie-png-fix property is set to true in IE6. - */ - isPngFix: function() { - var val = 0, el; - if( PIE.ieVersion < 7 ) { - el = this.targetElement; - val = ( '' + ( el.style[ PIE.STYLE_PREFIX + 'PngFix' ] || el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'png-fix' ) ) === 'true' ); - } - return val; - }, - - /** - * The isActive logic is slightly different, because getProps() always returns an object - * even if it is just falling back to the native background properties. But we only want - * to report is as being "active" if either the -pie-background override property is present - * and parses successfully or '-pie-png-fix' is set to true in IE6. - */ - isActive: PIE.StyleInfoBase.cacheWhenLocked( function() { - return (this.getCss3() || this.isPngFix()) && !!this.getProps(); - } ) - -} );/** - * Handles parsing, caching, and detecting changes to border CSS - * @constructor - * @param {Element} el the target element - */ -PIE.BorderStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - sides: [ 'Top', 'Right', 'Bottom', 'Left' ], - namedWidths: { - 'thin': '1px', - 'medium': '3px', - 'thick': '5px' - }, - - parseCss: function( css ) { - var w = {}, - s = {}, - c = {}, - active = false, - colorsSame = true, - stylesSame = true, - widthsSame = true; - - this.withActualBorder( function() { - var el = this.targetElement, - cs = el.currentStyle, - i = 0, - style, color, width, lastStyle, lastColor, lastWidth, side, ltr; - for( ; i < 4; i++ ) { - side = this.sides[ i ]; - - ltr = side.charAt(0).toLowerCase(); - style = s[ ltr ] = cs[ 'border' + side + 'Style' ]; - color = cs[ 'border' + side + 'Color' ]; - width = cs[ 'border' + side + 'Width' ]; - - if( i > 0 ) { - if( style !== lastStyle ) { stylesSame = false; } - if( color !== lastColor ) { colorsSame = false; } - if( width !== lastWidth ) { widthsSame = false; } - } - lastStyle = style; - lastColor = color; - lastWidth = width; - - c[ ltr ] = PIE.getColor( color ); - - width = w[ ltr ] = PIE.getLength( s[ ltr ] === 'none' ? '0' : ( this.namedWidths[ width ] || width ) ); - if( width.pixels( this.targetElement ) > 0 ) { - active = true; - } - } - } ); - - return active ? { - widths: w, - styles: s, - colors: c, - widthsSame: widthsSame, - colorsSame: colorsSame, - stylesSame: stylesSame - } : null; - }, - - getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { - var el = this.targetElement, - cs = el.currentStyle, - css; - - // Don't redraw or hide borders for cells in border-collapse:collapse tables - if( !( el.tagName in PIE.tableCellTags && el.offsetParent.currentStyle.borderCollapse === 'collapse' ) ) { - this.withActualBorder( function() { - css = cs.borderWidth + '|' + cs.borderStyle + '|' + cs.borderColor; - } ); - } - return css; - } ), - - /** - * Execute a function with the actual border styles (not overridden with runtimeStyle - * properties set by the renderers) available via currentStyle. - * @param fn - */ - withActualBorder: function( fn ) { - var rs = this.targetElement.runtimeStyle, - rsWidth = rs.borderWidth, - rsColor = rs.borderColor, - ret; - - if( rsWidth ) rs.borderWidth = ''; - if( rsColor ) rs.borderColor = ''; - - ret = fn.call( this ); - - if( rsWidth ) rs.borderWidth = rsWidth; - if( rsColor ) rs.borderColor = rsColor; - - return ret; - } - -} ); -/** - * Handles parsing, caching, and detecting changes to border-radius CSS - * @constructor - * @param {Element} el the target element - */ -(function() { - -PIE.BorderRadiusStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - cssProperty: 'border-radius', - styleProperty: 'borderRadius', - - parseCss: function( css ) { - var p = null, x, y, - tokenizer, token, length, - hasNonZero = false; - - if( css ) { - tokenizer = new PIE.Tokenizer( css ); - - function collectLengths() { - var arr = [], num; - while( ( token = tokenizer.next() ) && token.isLengthOrPercent() ) { - length = PIE.getLength( token.tokenValue ); - num = length.getNumber(); - if( num < 0 ) { - return null; - } - if( num > 0 ) { - hasNonZero = true; - } - arr.push( length ); - } - return arr.length > 0 && arr.length < 5 ? { - 'tl': arr[0], - 'tr': arr[1] || arr[0], - 'br': arr[2] || arr[0], - 'bl': arr[3] || arr[1] || arr[0] - } : null; - } - - // Grab the initial sequence of lengths - if( x = collectLengths() ) { - // See if there is a slash followed by more lengths, for the y-axis radii - if( token ) { - if( token.tokenType & PIE.Tokenizer.Type.OPERATOR && token.tokenValue === '/' ) { - y = collectLengths(); - } - } else { - y = x; - } - - // Treat all-zero values the same as no value - if( hasNonZero && x && y ) { - p = { x: x, y : y }; - } - } - } - - return p; - } -} ); - -var zero = PIE.getLength( '0' ), - zeros = { 'tl': zero, 'tr': zero, 'br': zero, 'bl': zero }; -PIE.BorderRadiusStyleInfo.ALL_ZERO = { x: zeros, y: zeros }; - -})();/** - * Handles parsing, caching, and detecting changes to border-image CSS - * @constructor - * @param {Element} el the target element - */ -PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - cssProperty: 'border-image', - styleProperty: 'borderImage', - - repeatIdents: { 'stretch':1, 'round':1, 'repeat':1, 'space':1 }, - - parseCss: function( css ) { - var p = null, tokenizer, token, type, value, - slices, widths, outsets, - slashCount = 0, - Type = PIE.Tokenizer.Type, - IDENT = Type.IDENT, - NUMBER = Type.NUMBER, - PERCENT = Type.PERCENT; - - if( css ) { - tokenizer = new PIE.Tokenizer( css ); - p = {}; - - function isSlash( token ) { - return token && ( token.tokenType & Type.OPERATOR ) && ( token.tokenValue === '/' ); - } - - function isFillIdent( token ) { - return token && ( token.tokenType & IDENT ) && ( token.tokenValue === 'fill' ); - } - - function collectSlicesEtc() { - slices = tokenizer.until( function( tok ) { - return !( tok.tokenType & ( NUMBER | PERCENT ) ); - } ); - - if( isFillIdent( tokenizer.next() ) && !p.fill ) { - p.fill = true; - } else { - tokenizer.prev(); - } - - if( isSlash( tokenizer.next() ) ) { - slashCount++; - widths = tokenizer.until( function( token ) { - return !token.isLengthOrPercent() && !( ( token.tokenType & IDENT ) && token.tokenValue === 'auto' ); - } ); - - if( isSlash( tokenizer.next() ) ) { - slashCount++; - outsets = tokenizer.until( function( token ) { - return !token.isLength(); - } ); - } - } else { - tokenizer.prev(); - } - } - - while( token = tokenizer.next() ) { - type = token.tokenType; - value = token.tokenValue; - - // Numbers and/or 'fill' keyword: slice values. May be followed optionally by width values, followed optionally by outset values - if( type & ( NUMBER | PERCENT ) && !slices ) { - tokenizer.prev(); - collectSlicesEtc(); - } - else if( isFillIdent( token ) && !p.fill ) { - p.fill = true; - collectSlicesEtc(); - } - - // Idents: one or values for 'repeat' - else if( ( type & IDENT ) && this.repeatIdents[value] && !p.repeat ) { - p.repeat = { h: value }; - if( token = tokenizer.next() ) { - if( ( token.tokenType & IDENT ) && this.repeatIdents[token.tokenValue] ) { - p.repeat.v = token.tokenValue; - } else { - tokenizer.prev(); - } - } - } - - // URL of the image - else if( ( type & Type.URL ) && !p.src ) { - p.src = value; - } - - // Found something unrecognized; exit. - else { - return null; - } - } - - // Validate what we collected - if( !p.src || !slices || slices.length < 1 || slices.length > 4 || - ( widths && widths.length > 4 ) || ( slashCount === 1 && widths.length < 1 ) || - ( outsets && outsets.length > 4 ) || ( slashCount === 2 && outsets.length < 1 ) ) { - return null; - } - - // Fill in missing values - if( !p.repeat ) { - p.repeat = { h: 'stretch' }; - } - if( !p.repeat.v ) { - p.repeat.v = p.repeat.h; - } - - function distributeSides( tokens, convertFn ) { - return { - 't': convertFn( tokens[0] ), - 'r': convertFn( tokens[1] || tokens[0] ), - 'b': convertFn( tokens[2] || tokens[0] ), - 'l': convertFn( tokens[3] || tokens[1] || tokens[0] ) - }; - } - - p.slice = distributeSides( slices, function( tok ) { - return PIE.getLength( ( tok.tokenType & NUMBER ) ? tok.tokenValue + 'px' : tok.tokenValue ); - } ); - - if( widths && widths[0] ) { - p.widths = distributeSides( widths, function( tok ) { - return tok.isLengthOrPercent() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; - } ); - } - - if( outsets && outsets[0] ) { - p.outset = distributeSides( outsets, function( tok ) { - return tok.isLength() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; - } ); - } - } - - return p; - } - -} );/** - * Handles parsing, caching, and detecting changes to box-shadow CSS - * @constructor - * @param {Element} el the target element - */ -PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - cssProperty: 'box-shadow', - styleProperty: 'boxShadow', - - parseCss: function( css ) { - var props, - getLength = PIE.getLength, - Type = PIE.Tokenizer.Type, - tokenizer; - - if( css ) { - tokenizer = new PIE.Tokenizer( css ); - props = { outset: [], inset: [] }; - - function parseItem() { - var token, type, value, color, lengths, inset, len; - - while( token = tokenizer.next() ) { - value = token.tokenValue; - type = token.tokenType; - - if( type & Type.OPERATOR && value === ',' ) { - break; - } - else if( token.isLength() && !lengths ) { - tokenizer.prev(); - lengths = tokenizer.until( function( token ) { - return !token.isLength(); - } ); - } - else if( type & Type.COLOR && !color ) { - color = value; - } - else if( type & Type.IDENT && value === 'inset' && !inset ) { - inset = true; - } - else { //encountered an unrecognized token; fail. - return false; - } - } - - len = lengths && lengths.length; - if( len > 1 && len < 5 ) { - ( inset ? props.inset : props.outset ).push( { - xOffset: getLength( lengths[0].tokenValue ), - yOffset: getLength( lengths[1].tokenValue ), - blur: getLength( lengths[2] ? lengths[2].tokenValue : '0' ), - spread: getLength( lengths[3] ? lengths[3].tokenValue : '0' ), - color: PIE.getColor( color || 'currentColor' ) - } ); - return true; - } - return false; - } - - while( parseItem() ) {} - } - - return props && ( props.inset.length || props.outset.length ) ? props : null; - } -} ); -/** - * Retrieves the state of the element's visibility and display - * @constructor - * @param {Element} el the target element - */ -PIE.VisibilityStyleInfo = PIE.StyleInfoBase.newStyleInfo( { - - getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { - var cs = this.targetElement.currentStyle; - return cs.visibility + '|' + cs.display; - } ), - - parseCss: function() { - var el = this.targetElement, - rs = el.runtimeStyle, - cs = el.currentStyle, - rsVis = rs.visibility, - csVis; - - rs.visibility = ''; - csVis = cs.visibility; - rs.visibility = rsVis; - - return { - visible: csVis !== 'hidden', - displayed: cs.display !== 'none' - } - }, - - /** - * Always return false for isActive, since this property alone will not trigger - * a renderer to do anything. - */ - isActive: function() { - return false; - } - -} ); -PIE.RendererBase = { - - /** - * Create a new Renderer class, with the standard constructor, and augmented by - * the RendererBase's members. - * @param proto - */ - newRenderer: function( proto ) { - function Renderer( el, boundsInfo, styleInfos, parent ) { - this.targetElement = el; - this.boundsInfo = boundsInfo; - this.styleInfos = styleInfos; - this.parent = parent; - } - PIE.Util.merge( Renderer.prototype, PIE.RendererBase, proto ); - return Renderer; - }, - - /** - * Flag indicating the element has already been positioned at least once. - * @type {boolean} - */ - isPositioned: false, - - /** - * Determine if the renderer needs to be updated - * @return {boolean} - */ - needsUpdate: function() { - return false; - }, - - /** - * Run any preparation logic that would affect the main update logic of this - * renderer or any of the other renderers, e.g. things that might affect the - * element's size or style properties. - */ - prepareUpdate: PIE.emptyFn, - - /** - * Tell the renderer to update based on modified properties - */ - updateProps: function() { - this.destroy(); - if( this.isActive() ) { - this.draw(); - } - }, - - /** - * Tell the renderer to update based on modified element position - */ - updatePos: function() { - this.isPositioned = true; - }, - - /** - * Tell the renderer to update based on modified element dimensions - */ - updateSize: function() { - if( this.isActive() ) { - this.draw(); - } else { - this.destroy(); - } - }, - - - /** - * Add a layer element, with the given z-order index, to the renderer's main box element. We can't use - * z-index because that breaks when the root rendering box's z-index is 'auto' in IE8+ standards mode. - * So instead we make sure they are inserted into the DOM in the correct order. - * @param {number} index - * @param {Element} el - */ - addLayer: function( index, el ) { - this.removeLayer( index ); - for( var layers = this._layers || ( this._layers = [] ), i = index + 1, len = layers.length, layer; i < len; i++ ) { - layer = layers[i]; - if( layer ) { - break; - } - } - layers[index] = el; - this.getBox().insertBefore( el, layer || null ); - }, - - /** - * Retrieve a layer element by its index, or null if not present - * @param {number} index - * @return {Element} - */ - getLayer: function( index ) { - var layers = this._layers; - return layers && layers[index] || null; - }, - - /** - * Remove a layer element by its index - * @param {number} index - */ - removeLayer: function( index ) { - var layer = this.getLayer( index ), - box = this._box; - if( layer && box ) { - box.removeChild( layer ); - this._layers[index] = null; - } - }, - - - /** - * Get a VML shape by name, creating it if necessary. - * @param {string} name A name identifying the element - * @param {string=} subElName If specified a subelement of the shape will be created with this tag name - * @param {Element} parent The parent element for the shape; will be ignored if 'group' is specified - * @param {number=} group If specified, an ordinal group for the shape. 1 or greater. Groups are rendered - * using container elements in the correct order, to get correct z stacking without z-index. - */ - getShape: function( name, subElName, parent, group ) { - var shapes = this._shapes || ( this._shapes = {} ), - shape = shapes[ name ], - s; - - if( !shape ) { - shape = shapes[ name ] = PIE.Util.createVmlElement( 'shape' ); - if( subElName ) { - shape.appendChild( shape[ subElName ] = PIE.Util.createVmlElement( subElName ) ); - } - - if( group ) { - parent = this.getLayer( group ); - if( !parent ) { - this.addLayer( group, doc.createElement( 'group' + group ) ); - parent = this.getLayer( group ); - } - } - - parent.appendChild( shape ); - - s = shape.style; - s.position = 'absolute'; - s.left = s.top = 0; - s['behavior'] = 'url(#default#VML)'; - } - return shape; - }, - - /** - * Delete a named shape which was created by getShape(). Returns true if a shape with the - * given name was found and deleted, or false if there was no shape of that name. - * @param {string} name - * @return {boolean} - */ - deleteShape: function( name ) { - var shapes = this._shapes, - shape = shapes && shapes[ name ]; - if( shape ) { - shape.parentNode.removeChild( shape ); - delete shapes[ name ]; - } - return !!shape; - }, - - - /** - * For a given set of border radius length/percentage values, convert them to concrete pixel - * values based on the current size of the target element. - * @param {Object} radii - * @return {Object} - */ - getRadiiPixels: function( radii ) { - var el = this.targetElement, - bounds = this.boundsInfo.getBounds(), - w = bounds.w, - h = bounds.h, - tlX, tlY, trX, trY, brX, brY, blX, blY, f; - - tlX = radii.x['tl'].pixels( el, w ); - tlY = radii.y['tl'].pixels( el, h ); - trX = radii.x['tr'].pixels( el, w ); - trY = radii.y['tr'].pixels( el, h ); - brX = radii.x['br'].pixels( el, w ); - brY = radii.y['br'].pixels( el, h ); - blX = radii.x['bl'].pixels( el, w ); - blY = radii.y['bl'].pixels( el, h ); - - // If any corner ellipses overlap, reduce them all by the appropriate factor. This formula - // is taken straight from the CSS3 Backgrounds and Borders spec. - f = Math.min( - w / ( tlX + trX ), - h / ( trY + brY ), - w / ( blX + brX ), - h / ( tlY + blY ) - ); - if( f < 1 ) { - tlX *= f; - tlY *= f; - trX *= f; - trY *= f; - brX *= f; - brY *= f; - blX *= f; - blY *= f; - } - - return { - x: { - 'tl': tlX, - 'tr': trX, - 'br': brX, - 'bl': blX - }, - y: { - 'tl': tlY, - 'tr': trY, - 'br': brY, - 'bl': blY - } - } - }, - - /** - * Return the VML path string for the element's background box, with corners rounded. - * @param {Object.<{t:number, r:number, b:number, l:number}>} shrink - if present, specifies number of - * pixels to shrink the box path inward from the element's four sides. - * @param {number=} mult If specified, all coordinates will be multiplied by this number - * @param {Object=} radii If specified, this will be used for the corner radii instead of the properties - * from this renderer's borderRadiusInfo object. - * @return {string} the VML path - */ - getBoxPath: function( shrink, mult, radii ) { - mult = mult || 1; - - var r, str, - bounds = this.boundsInfo.getBounds(), - w = bounds.w * mult, - h = bounds.h * mult, - radInfo = this.styleInfos.borderRadiusInfo, - floor = Math.floor, ceil = Math.ceil, - shrinkT = shrink ? shrink.t * mult : 0, - shrinkR = shrink ? shrink.r * mult : 0, - shrinkB = shrink ? shrink.b * mult : 0, - shrinkL = shrink ? shrink.l * mult : 0, - tlX, tlY, trX, trY, brX, brY, blX, blY; - - if( radii || radInfo.isActive() ) { - r = this.getRadiiPixels( radii || radInfo.getProps() ); - - tlX = r.x['tl'] * mult; - tlY = r.y['tl'] * mult; - trX = r.x['tr'] * mult; - trY = r.y['tr'] * mult; - brX = r.x['br'] * mult; - brY = r.y['br'] * mult; - blX = r.x['bl'] * mult; - blY = r.y['bl'] * mult; - - str = 'm' + floor( shrinkL ) + ',' + floor( tlY ) + - 'qy' + floor( tlX ) + ',' + floor( shrinkT ) + - 'l' + ceil( w - trX ) + ',' + floor( shrinkT ) + - 'qx' + ceil( w - shrinkR ) + ',' + floor( trY ) + - 'l' + ceil( w - shrinkR ) + ',' + ceil( h - brY ) + - 'qy' + ceil( w - brX ) + ',' + ceil( h - shrinkB ) + - 'l' + floor( blX ) + ',' + ceil( h - shrinkB ) + - 'qx' + floor( shrinkL ) + ',' + ceil( h - blY ) + ' x e'; - } else { - // simplified path for non-rounded box - str = 'm' + floor( shrinkL ) + ',' + floor( shrinkT ) + - 'l' + ceil( w - shrinkR ) + ',' + floor( shrinkT ) + - 'l' + ceil( w - shrinkR ) + ',' + ceil( h - shrinkB ) + - 'l' + floor( shrinkL ) + ',' + ceil( h - shrinkB ) + - 'xe'; - } - return str; - }, - - - /** - * Get the container element for the shapes, creating it if necessary. - */ - getBox: function() { - var box = this.parent.getLayer( this.boxZIndex ), s; - - if( !box ) { - box = doc.createElement( this.boxName ); - s = box.style; - s.position = 'absolute'; - s.top = s.left = 0; - this.parent.addLayer( this.boxZIndex, box ); - } - - return box; - }, - - - /** - * Hide the actual border of the element. In IE7 and up we can just set its color to transparent; - * however IE6 does not support transparent borders so we have to get tricky with it. Also, some elements - * like form buttons require removing the border width altogether, so for those we increase the padding - * by the border size. - */ - hideBorder: function() { - var el = this.targetElement, - cs = el.currentStyle, - rs = el.runtimeStyle, - tag = el.tagName, - isIE6 = PIE.ieVersion === 6, - sides, side, i; - - if( ( isIE6 && ( tag in PIE.childlessElements || tag === 'FIELDSET' ) ) || - tag === 'BUTTON' || ( tag === 'INPUT' && el.type in PIE.inputButtonTypes ) ) { - rs.borderWidth = ''; - sides = this.styleInfos.borderInfo.sides; - for( i = sides.length; i--; ) { - side = sides[ i ]; - rs[ 'padding' + side ] = ''; - rs[ 'padding' + side ] = ( PIE.getLength( cs[ 'padding' + side ] ) ).pixels( el ) + - ( PIE.getLength( cs[ 'border' + side + 'Width' ] ) ).pixels( el ) + - ( PIE.ieVersion !== 8 && i % 2 ? 1 : 0 ); //needs an extra horizontal pixel to counteract the extra "inner border" going away - } - rs.borderWidth = 0; - } - else if( isIE6 ) { - // Wrap all the element's children in a custom element, set the element to visiblity:hidden, - // and set the wrapper element to visiblity:visible. This hides the outer element's decorations - // (background and border) but displays all the contents. - // TODO find a better way to do this that doesn't mess up the DOM parent-child relationship, - // as this can interfere with other author scripts which add/modify/delete children. Also, this - // won't work for elements which cannot take children, e.g. input/button/textarea/img/etc. Look into - // using a compositor filter or some other filter which masks the border. - if( el.childNodes.length !== 1 || el.firstChild.tagName !== 'ie6-mask' ) { - var cont = doc.createElement( 'ie6-mask' ), - s = cont.style, child; - s.visibility = 'visible'; - s.zoom = 1; - while( child = el.firstChild ) { - cont.appendChild( child ); - } - el.appendChild( cont ); - rs.visibility = 'hidden'; - } - } - else { - rs.borderColor = 'transparent'; - } - }, - - unhideBorder: function() { - - }, - - - /** - * Destroy the rendered objects. This is a base implementation which handles common renderer - * structures, but individual renderers may override as necessary. - */ - destroy: function() { - this.parent.removeLayer( this.boxZIndex ); - delete this._shapes; - delete this._layers; - } -}; -/** - * Root renderer; creates the outermost container element and handles keeping it aligned - * with the target element's size and position. - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - */ -PIE.RootRenderer = PIE.RendererBase.newRenderer( { - - isActive: function() { - var children = this.childRenderers; - for( var i in children ) { - if( children.hasOwnProperty( i ) && children[ i ].isActive() ) { - return true; - } - } - return false; - }, - - needsUpdate: function() { - return this.styleInfos.visibilityInfo.changed(); - }, - - updatePos: function() { - if( this.isActive() ) { - var el = this.getPositioningElement(), - par = el, - docEl, - parRect, - tgtCS = el.currentStyle, - tgtPos = tgtCS.position, - boxPos, - s = this.getBox().style, cs, - x = 0, y = 0, - elBounds = this.boundsInfo.getBounds(), - logicalZoomRatio = elBounds.logicalZoomRatio; - - if( tgtPos === 'fixed' && PIE.ieVersion > 6 ) { - x = elBounds.x * logicalZoomRatio; - y = elBounds.y * logicalZoomRatio; - boxPos = tgtPos; - } else { - // Get the element's offsets from its nearest positioned ancestor. Uses - // getBoundingClientRect for accuracy and speed. - do { - par = par.offsetParent; - } while( par && ( par.currentStyle.position === 'static' ) ); - if( par ) { - parRect = par.getBoundingClientRect(); - cs = par.currentStyle; - x = ( elBounds.x - parRect.left ) * logicalZoomRatio - ( parseFloat(cs.borderLeftWidth) || 0 ); - y = ( elBounds.y - parRect.top ) * logicalZoomRatio - ( parseFloat(cs.borderTopWidth) || 0 ); - } else { - docEl = doc.documentElement; - x = ( elBounds.x + docEl.scrollLeft - docEl.clientLeft ) * logicalZoomRatio; - y = ( elBounds.y + docEl.scrollTop - docEl.clientTop ) * logicalZoomRatio; - } - boxPos = 'absolute'; - } - - s.position = boxPos; - s.left = x; - s.top = y; - s.zIndex = tgtPos === 'static' ? -1 : tgtCS.zIndex; - this.isPositioned = true; - } - }, - - updateSize: PIE.emptyFn, - - updateVisibility: function() { - var vis = this.styleInfos.visibilityInfo.getProps(); - this.getBox().style.display = ( vis.visible && vis.displayed ) ? '' : 'none'; - }, - - updateProps: function() { - if( this.isActive() ) { - this.updateVisibility(); - } else { - this.destroy(); - } - }, - - getPositioningElement: function() { - var el = this.targetElement; - return el.tagName in PIE.tableCellTags ? el.offsetParent : el; - }, - - getBox: function() { - var box = this._box, el; - if( !box ) { - el = this.getPositioningElement(); - box = this._box = doc.createElement( 'css3-container' ); - box.style['direction'] = 'ltr'; //fix positioning bug in rtl environments - - this.updateVisibility(); - - el.parentNode.insertBefore( box, el ); - } - return box; - }, - - finishUpdate: PIE.emptyFn, - - destroy: function() { - var box = this._box, par; - if( box && ( par = box.parentNode ) ) { - par.removeChild( box ); - } - delete this._box; - delete this._layers; - } - -} ); -/** - * Renderer for element backgrounds. - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { - - boxZIndex: 2, - boxName: 'background', - - needsUpdate: function() { - var si = this.styleInfos; - return si.backgroundInfo.changed() || si.borderRadiusInfo.changed(); - }, - - isActive: function() { - var si = this.styleInfos; - return si.borderImageInfo.isActive() || - si.borderRadiusInfo.isActive() || - si.backgroundInfo.isActive() || - ( si.boxShadowInfo.isActive() && si.boxShadowInfo.getProps().inset ); - }, - - /** - * Draw the shapes - */ - draw: function() { - var bounds = this.boundsInfo.getBounds(); - if( bounds.w && bounds.h ) { - this.drawBgColor(); - this.drawBgImages(); - } - }, - - /** - * Draw the background color shape - */ - drawBgColor: function() { - var props = this.styleInfos.backgroundInfo.getProps(), - bounds = this.boundsInfo.getBounds(), - el = this.targetElement, - color = props && props.color, - shape, w, h, s, alpha; - - if( color && color.alpha() > 0 ) { - this.hideBackground(); - - shape = this.getShape( 'bgColor', 'fill', this.getBox(), 1 ); - w = bounds.w; - h = bounds.h; - shape.stroked = false; - shape.coordsize = w * 2 + ',' + h * 2; - shape.coordorigin = '1,1'; - shape.path = this.getBoxPath( null, 2 ); - s = shape.style; - s.width = w; - s.height = h; - shape.fill.color = color.colorValue( el ); - - alpha = color.alpha(); - if( alpha < 1 ) { - shape.fill.opacity = alpha; - } - } else { - this.deleteShape( 'bgColor' ); - } - }, - - /** - * Draw all the background image layers - */ - drawBgImages: function() { - var props = this.styleInfos.backgroundInfo.getProps(), - bounds = this.boundsInfo.getBounds(), - images = props && props.bgImages, - img, shape, w, h, s, i; - - if( images ) { - this.hideBackground(); - - w = bounds.w; - h = bounds.h; - - i = images.length; - while( i-- ) { - img = images[i]; - shape = this.getShape( 'bgImage' + i, 'fill', this.getBox(), 2 ); - - shape.stroked = false; - shape.fill.type = 'tile'; - shape.fillcolor = 'none'; - shape.coordsize = w * 2 + ',' + h * 2; - shape.coordorigin = '1,1'; - shape.path = this.getBoxPath( 0, 2 ); - s = shape.style; - s.width = w; - s.height = h; - - if( img.imgType === 'linear-gradient' ) { - this.addLinearGradient( shape, img ); - } - else { - shape.fill.src = img.imgUrl; - this.positionBgImage( shape, i ); - } - } - } - - // Delete any bgImage shapes previously created which weren't used above - i = images ? images.length : 0; - while( this.deleteShape( 'bgImage' + i++ ) ) {} - }, - - - /** - * Set the position and clipping of the background image for a layer - * @param {Element} shape - * @param {number} index - */ - positionBgImage: function( shape, index ) { - var me = this; - PIE.Util.withImageSize( shape.fill.src, function( size ) { - var el = me.targetElement, - bounds = me.boundsInfo.getBounds(), - elW = bounds.w, - elH = bounds.h; - - // It's possible that the element dimensions are zero now but weren't when the original - // update executed, make sure that's not the case to avoid divide-by-zero error - if( elW && elH ) { - var fill = shape.fill, - si = me.styleInfos, - border = si.borderInfo.getProps(), - bw = border && border.widths, - bwT = bw ? bw['t'].pixels( el ) : 0, - bwR = bw ? bw['r'].pixels( el ) : 0, - bwB = bw ? bw['b'].pixels( el ) : 0, - bwL = bw ? bw['l'].pixels( el ) : 0, - bg = si.backgroundInfo.getProps().bgImages[ index ], - bgPos = bg.bgPosition ? bg.bgPosition.coords( el, elW - size.w - bwL - bwR, elH - size.h - bwT - bwB ) : { x:0, y:0 }, - repeat = bg.imgRepeat, - pxX, pxY, - clipT = 0, clipL = 0, - clipR = elW + 1, clipB = elH + 1, //make sure the default clip region is not inside the box (by a subpixel) - clipAdjust = PIE.ieVersion === 8 ? 0 : 1; //prior to IE8 requires 1 extra pixel in the image clip region - - // Positioning - find the pixel offset from the top/left and convert to a ratio - // The position is shifted by half a pixel, to adjust for the half-pixel coordorigin shift which is - // needed to fix antialiasing but makes the bg image fuzzy. - pxX = Math.round( bgPos.x ) + bwL + 0.5; - pxY = Math.round( bgPos.y ) + bwT + 0.5; - fill.position = ( pxX / elW ) + ',' + ( pxY / elH ); - - // Set the size of the image. We have to actually set it to px values otherwise it will not honor - // the user's browser zoom level and always display at its natural screen size. - fill['size']['x'] = 1; //Can be any value, just has to be set to "prime" it so the next line works. Weird! - fill['size'] = size.w + 'px,' + size.h + 'px'; - - // Repeating - clip the image shape - if( repeat && repeat !== 'repeat' ) { - if( repeat === 'repeat-x' || repeat === 'no-repeat' ) { - clipT = pxY + 1; - clipB = pxY + size.h + clipAdjust; - } - if( repeat === 'repeat-y' || repeat === 'no-repeat' ) { - clipL = pxX + 1; - clipR = pxX + size.w + clipAdjust; - } - shape.style.clip = 'rect(' + clipT + 'px,' + clipR + 'px,' + clipB + 'px,' + clipL + 'px)'; - } - } - } ); - }, - - - /** - * Draw the linear gradient for a gradient layer - * @param {Element} shape - * @param {Object} info The object holding the information about the gradient - */ - addLinearGradient: function( shape, info ) { - var el = this.targetElement, - bounds = this.boundsInfo.getBounds(), - w = bounds.w, - h = bounds.h, - fill = shape.fill, - stops = info.stops, - stopCount = stops.length, - PI = Math.PI, - GradientUtil = PIE.GradientUtil, - perpendicularIntersect = GradientUtil.perpendicularIntersect, - distance = GradientUtil.distance, - metrics = GradientUtil.getGradientMetrics( el, w, h, info ), - angle = metrics.angle, - startX = metrics.startX, - startY = metrics.startY, - startCornerX = metrics.startCornerX, - startCornerY = metrics.startCornerY, - endCornerX = metrics.endCornerX, - endCornerY = metrics.endCornerY, - deltaX = metrics.deltaX, - deltaY = metrics.deltaY, - lineLength = metrics.lineLength, - vmlAngle, vmlGradientLength, vmlColors, - stopPx, vmlOffsetPct, - p, i, j, before, after; - - // In VML land, the angle of the rendered gradient depends on the aspect ratio of the shape's - // bounding box; for example specifying a 45 deg angle actually results in a gradient - // drawn diagonally from one corner to its opposite corner, which will only appear to the - // viewer as 45 degrees if the shape is equilateral. We adjust for this by taking the x/y deltas - // between the start and end points, multiply one of them by the shape's aspect ratio, - // and get their arctangent, resulting in an appropriate VML angle. If the angle is perfectly - // horizontal or vertical then we don't need to do this conversion. - vmlAngle = ( angle % 90 ) ? Math.atan2( deltaX * w / h, deltaY ) / PI * 180 : ( angle + 90 ); - - // VML angles are 180 degrees offset from CSS angles - vmlAngle += 180; - vmlAngle = vmlAngle % 360; - - // Add all the stops to the VML 'colors' list, including the first and last stops. - // For each, we find its pixel offset along the gradient-line; if the offset of a stop is less - // than that of its predecessor we increase it to be equal. We then map that pixel offset to a - // percentage along the VML gradient-line, which runs from shape corner to corner. - p = perpendicularIntersect( startCornerX, startCornerY, angle, endCornerX, endCornerY ); - vmlGradientLength = distance( startCornerX, startCornerY, p[0], p[1] ); - vmlColors = []; - p = perpendicularIntersect( startX, startY, angle, startCornerX, startCornerY ); - vmlOffsetPct = distance( startX, startY, p[0], p[1] ) / vmlGradientLength * 100; - - // Find the pixel offsets along the CSS3 gradient-line for each stop. - stopPx = []; - for( i = 0; i < stopCount; i++ ) { - stopPx.push( stops[i].offset ? stops[i].offset.pixels( el, lineLength ) : - i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); - } - // Fill in gaps with evenly-spaced offsets - for( i = 1; i < stopCount; i++ ) { - if( stopPx[ i ] === null ) { - before = stopPx[ i - 1 ]; - j = i; - do { - after = stopPx[ ++j ]; - } while( after === null ); - stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); - } - // Make sure each stop's offset is no less than the one before it - stopPx[ i ] = Math.max( stopPx[ i ], stopPx[ i - 1 ] ); - } - - // Convert to percentage along the VML gradient line and add to the VML 'colors' value - for( i = 0; i < stopCount; i++ ) { - vmlColors.push( - ( vmlOffsetPct + ( stopPx[ i ] / vmlGradientLength * 100 ) ) + '% ' + stops[i].color.colorValue( el ) - ); - } - - // Now, finally, we're ready to render the gradient fill. Set the start and end colors to - // the first and last stop colors; this just sets outer bounds for the gradient. - fill['angle'] = vmlAngle; - fill['type'] = 'gradient'; - fill['method'] = 'sigma'; - fill['color'] = stops[0].color.colorValue( el ); - fill['color2'] = stops[stopCount - 1].color.colorValue( el ); - if( fill['colors'] ) { //sometimes the colors object isn't initialized so we have to assign it directly (?) - fill['colors'].value = vmlColors.join( ',' ); - } else { - fill['colors'] = vmlColors.join( ',' ); - } - }, - - - /** - * Hide the actual background image and color of the element. - */ - hideBackground: function() { - var rs = this.targetElement.runtimeStyle; - rs.backgroundImage = 'url(about:blank)'; //ensures the background area reacts to mouse events - rs.backgroundColor = 'transparent'; - }, - - destroy: function() { - PIE.RendererBase.destroy.call( this ); - var rs = this.targetElement.runtimeStyle; - rs.backgroundImage = rs.backgroundColor = ''; - } - -} ); -/** - * Renderer for element borders. - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.BorderRenderer = PIE.RendererBase.newRenderer( { - - boxZIndex: 4, - boxName: 'border', - - needsUpdate: function() { - var si = this.styleInfos; - return si.borderInfo.changed() || si.borderRadiusInfo.changed(); - }, - - isActive: function() { - var si = this.styleInfos; - return si.borderRadiusInfo.isActive() && - !si.borderImageInfo.isActive() && - si.borderInfo.isActive(); //check BorderStyleInfo last because it's the most expensive - }, - - /** - * Draw the border shape(s) - */ - draw: function() { - var el = this.targetElement, - props = this.styleInfos.borderInfo.getProps(), - bounds = this.boundsInfo.getBounds(), - w = bounds.w, - h = bounds.h, - shape, stroke, s, - segments, seg, i, len; - - if( props ) { - this.hideBorder(); - - segments = this.getBorderSegments( 2 ); - for( i = 0, len = segments.length; i < len; i++) { - seg = segments[i]; - shape = this.getShape( 'borderPiece' + i, seg.stroke ? 'stroke' : 'fill', this.getBox() ); - shape.coordsize = w * 2 + ',' + h * 2; - shape.coordorigin = '1,1'; - shape.path = seg.path; - s = shape.style; - s.width = w; - s.height = h; - - shape.filled = !!seg.fill; - shape.stroked = !!seg.stroke; - if( seg.stroke ) { - stroke = shape.stroke; - stroke['weight'] = seg.weight + 'px'; - stroke.color = seg.color.colorValue( el ); - stroke['dashstyle'] = seg.stroke === 'dashed' ? '2 2' : seg.stroke === 'dotted' ? '1 1' : 'solid'; - stroke['linestyle'] = seg.stroke === 'double' && seg.weight > 2 ? 'ThinThin' : 'Single'; - } else { - shape.fill.color = seg.fill.colorValue( el ); - } - } - - // remove any previously-created border shapes which didn't get used above - while( this.deleteShape( 'borderPiece' + i++ ) ) {} - } - }, - - - /** - * Get the VML path definitions for the border segment(s). - * @param {number=} mult If specified, all coordinates will be multiplied by this number - * @return {Array.} - */ - getBorderSegments: function( mult ) { - var el = this.targetElement, - bounds, elW, elH, - borderInfo = this.styleInfos.borderInfo, - segments = [], - floor, ceil, wT, wR, wB, wL, - round = Math.round, - borderProps, radiusInfo, radii, widths, styles, colors; - - if( borderInfo.isActive() ) { - borderProps = borderInfo.getProps(); - - widths = borderProps.widths; - styles = borderProps.styles; - colors = borderProps.colors; - - if( borderProps.widthsSame && borderProps.stylesSame && borderProps.colorsSame ) { - if( colors['t'].alpha() > 0 ) { - // shortcut for identical border on all sides - only need 1 stroked shape - wT = widths['t'].pixels( el ); //thickness - wR = wT / 2; //shrink - segments.push( { - path: this.getBoxPath( { t: wR, r: wR, b: wR, l: wR }, mult ), - stroke: styles['t'], - color: colors['t'], - weight: wT - } ); - } - } - else { - mult = mult || 1; - bounds = this.boundsInfo.getBounds(); - elW = bounds.w; - elH = bounds.h; - - wT = round( widths['t'].pixels( el ) ); - wR = round( widths['r'].pixels( el ) ); - wB = round( widths['b'].pixels( el ) ); - wL = round( widths['l'].pixels( el ) ); - var pxWidths = { - 't': wT, - 'r': wR, - 'b': wB, - 'l': wL - }; - - radiusInfo = this.styleInfos.borderRadiusInfo; - if( radiusInfo.isActive() ) { - radii = this.getRadiiPixels( radiusInfo.getProps() ); - } - - floor = Math.floor; - ceil = Math.ceil; - - function radius( xy, corner ) { - return radii ? radii[ xy ][ corner ] : 0; - } - - function curve( corner, shrinkX, shrinkY, startAngle, ccw, doMove ) { - var rx = radius( 'x', corner), - ry = radius( 'y', corner), - deg = 65535, - isRight = corner.charAt( 1 ) === 'r', - isBottom = corner.charAt( 0 ) === 'b'; - return ( rx > 0 && ry > 0 ) ? - ( doMove ? 'al' : 'ae' ) + - ( isRight ? ceil( elW - rx ) : floor( rx ) ) * mult + ',' + // center x - ( isBottom ? ceil( elH - ry ) : floor( ry ) ) * mult + ',' + // center y - ( floor( rx ) - shrinkX ) * mult + ',' + // width - ( floor( ry ) - shrinkY ) * mult + ',' + // height - ( startAngle * deg ) + ',' + // start angle - ( 45 * deg * ( ccw ? 1 : -1 ) // angle change - ) : ( - ( doMove ? 'm' : 'l' ) + - ( isRight ? elW - shrinkX : shrinkX ) * mult + ',' + - ( isBottom ? elH - shrinkY : shrinkY ) * mult - ); - } - - function line( side, shrink, ccw, doMove ) { - var - start = ( - side === 't' ? - floor( radius( 'x', 'tl') ) * mult + ',' + ceil( shrink ) * mult : - side === 'r' ? - ceil( elW - shrink ) * mult + ',' + floor( radius( 'y', 'tr') ) * mult : - side === 'b' ? - ceil( elW - radius( 'x', 'br') ) * mult + ',' + floor( elH - shrink ) * mult : - // side === 'l' ? - floor( shrink ) * mult + ',' + ceil( elH - radius( 'y', 'bl') ) * mult - ), - end = ( - side === 't' ? - ceil( elW - radius( 'x', 'tr') ) * mult + ',' + ceil( shrink ) * mult : - side === 'r' ? - ceil( elW - shrink ) * mult + ',' + ceil( elH - radius( 'y', 'br') ) * mult : - side === 'b' ? - floor( radius( 'x', 'bl') ) * mult + ',' + floor( elH - shrink ) * mult : - // side === 'l' ? - floor( shrink ) * mult + ',' + floor( radius( 'y', 'tl') ) * mult - ); - return ccw ? ( doMove ? 'm' + end : '' ) + 'l' + start : - ( doMove ? 'm' + start : '' ) + 'l' + end; - } - - - function addSide( side, sideBefore, sideAfter, cornerBefore, cornerAfter, baseAngle ) { - var vert = side === 'l' || side === 'r', - sideW = pxWidths[ side ], - beforeX, beforeY, afterX, afterY; - - if( sideW > 0 && styles[ side ] !== 'none' && colors[ side ].alpha() > 0 ) { - beforeX = pxWidths[ vert ? side : sideBefore ]; - beforeY = pxWidths[ vert ? sideBefore : side ]; - afterX = pxWidths[ vert ? side : sideAfter ]; - afterY = pxWidths[ vert ? sideAfter : side ]; - - if( styles[ side ] === 'dashed' || styles[ side ] === 'dotted' ) { - segments.push( { - path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + - curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), - fill: colors[ side ] - } ); - segments.push( { - path: line( side, sideW / 2, 0, 1 ), - stroke: styles[ side ], - weight: sideW, - color: colors[ side ] - } ); - segments.push( { - path: curve( cornerAfter, afterX, afterY, baseAngle, 0, 1 ) + - curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ), - fill: colors[ side ] - } ); - } - else { - segments.push( { - path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + - line( side, sideW, 0, 0 ) + - curve( cornerAfter, afterX, afterY, baseAngle, 0, 0 ) + - - ( styles[ side ] === 'double' && sideW > 2 ? - curve( cornerAfter, afterX - floor( afterX / 3 ), afterY - floor( afterY / 3 ), baseAngle - 45, 1, 0 ) + - line( side, ceil( sideW / 3 * 2 ), 1, 0 ) + - curve( cornerBefore, beforeX - floor( beforeX / 3 ), beforeY - floor( beforeY / 3 ), baseAngle, 1, 0 ) + - 'x ' + - curve( cornerBefore, floor( beforeX / 3 ), floor( beforeY / 3 ), baseAngle + 45, 0, 1 ) + - line( side, floor( sideW / 3 ), 1, 0 ) + - curve( cornerAfter, floor( afterX / 3 ), floor( afterY / 3 ), baseAngle, 0, 0 ) - : '' ) + - - curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ) + - line( side, 0, 1, 0 ) + - curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), - fill: colors[ side ] - } ); - } - } - } - - addSide( 't', 'l', 'r', 'tl', 'tr', 90 ); - addSide( 'r', 't', 'b', 'tr', 'br', 0 ); - addSide( 'b', 'r', 'l', 'br', 'bl', -90 ); - addSide( 'l', 'b', 't', 'bl', 'tl', -180 ); - } - } - - return segments; - }, - - destroy: function() { - var me = this; - if (me.finalized || !me.styleInfos.borderImageInfo.isActive()) { - me.targetElement.runtimeStyle.borderColor = ''; - } - PIE.RendererBase.destroy.call( me ); - } - - -} ); -/** - * Renderer for border-image - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.BorderImageRenderer = PIE.RendererBase.newRenderer( { - - boxZIndex: 5, - pieceNames: [ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl', 'c' ], - - needsUpdate: function() { - return this.styleInfos.borderImageInfo.changed(); - }, - - isActive: function() { - return this.styleInfos.borderImageInfo.isActive(); - }, - - draw: function() { - this.getBox(); //make sure pieces are created - - var props = this.styleInfos.borderImageInfo.getProps(), - borderProps = this.styleInfos.borderInfo.getProps(), - bounds = this.boundsInfo.getBounds(), - el = this.targetElement, - pieces = this.pieces; - - PIE.Util.withImageSize( props.src, function( imgSize ) { - var elW = bounds.w, - elH = bounds.h, - zero = PIE.getLength( '0' ), - widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), - widthT = widths['t'].pixels( el ), - widthR = widths['r'].pixels( el ), - widthB = widths['b'].pixels( el ), - widthL = widths['l'].pixels( el ), - slices = props.slice, - sliceT = slices['t'].pixels( el ), - sliceR = slices['r'].pixels( el ), - sliceB = slices['b'].pixels( el ), - sliceL = slices['l'].pixels( el ); - - // Piece positions and sizes - function setSizeAndPos( piece, w, h, x, y ) { - var s = pieces[piece].style, - max = Math.max; - s.width = max(w, 0); - s.height = max(h, 0); - s.left = x; - s.top = y; - } - setSizeAndPos( 'tl', widthL, widthT, 0, 0 ); - setSizeAndPos( 't', elW - widthL - widthR, widthT, widthL, 0 ); - setSizeAndPos( 'tr', widthR, widthT, elW - widthR, 0 ); - setSizeAndPos( 'r', widthR, elH - widthT - widthB, elW - widthR, widthT ); - setSizeAndPos( 'br', widthR, widthB, elW - widthR, elH - widthB ); - setSizeAndPos( 'b', elW - widthL - widthR, widthB, widthL, elH - widthB ); - setSizeAndPos( 'bl', widthL, widthB, 0, elH - widthB ); - setSizeAndPos( 'l', widthL, elH - widthT - widthB, 0, widthT ); - setSizeAndPos( 'c', elW - widthL - widthR, elH - widthT - widthB, widthL, widthT ); - - - // image croppings - function setCrops( sides, crop, val ) { - for( var i=0, len=sides.length; i < len; i++ ) { - pieces[ sides[i] ]['imagedata'][ crop ] = val; - } - } - - // corners - setCrops( [ 'tl', 't', 'tr' ], 'cropBottom', ( imgSize.h - sliceT ) / imgSize.h ); - setCrops( [ 'tl', 'l', 'bl' ], 'cropRight', ( imgSize.w - sliceL ) / imgSize.w ); - setCrops( [ 'bl', 'b', 'br' ], 'cropTop', ( imgSize.h - sliceB ) / imgSize.h ); - setCrops( [ 'tr', 'r', 'br' ], 'cropLeft', ( imgSize.w - sliceR ) / imgSize.w ); - - // edges and center - // TODO right now this treats everything like 'stretch', need to support other schemes - //if( props.repeat.v === 'stretch' ) { - setCrops( [ 'l', 'r', 'c' ], 'cropTop', sliceT / imgSize.h ); - setCrops( [ 'l', 'r', 'c' ], 'cropBottom', sliceB / imgSize.h ); - //} - //if( props.repeat.h === 'stretch' ) { - setCrops( [ 't', 'b', 'c' ], 'cropLeft', sliceL / imgSize.w ); - setCrops( [ 't', 'b', 'c' ], 'cropRight', sliceR / imgSize.w ); - //} - - // center fill - pieces['c'].style.display = props.fill ? '' : 'none'; - }, this ); - }, - - getBox: function() { - var box = this.parent.getLayer( this.boxZIndex ), - s, piece, i, - pieceNames = this.pieceNames, - len = pieceNames.length; - - if( !box ) { - box = doc.createElement( 'border-image' ); - s = box.style; - s.position = 'absolute'; - - this.pieces = {}; - - for( i = 0; i < len; i++ ) { - piece = this.pieces[ pieceNames[i] ] = PIE.Util.createVmlElement( 'rect' ); - piece.appendChild( PIE.Util.createVmlElement( 'imagedata' ) ); - s = piece.style; - s['behavior'] = 'url(#default#VML)'; - s.position = "absolute"; - s.top = s.left = 0; - piece['imagedata'].src = this.styleInfos.borderImageInfo.getProps().src; - piece.stroked = false; - piece.filled = false; - box.appendChild( piece ); - } - - this.parent.addLayer( this.boxZIndex, box ); - } - - return box; - }, - - prepareUpdate: function() { - if (this.isActive()) { - var me = this, - el = me.targetElement, - rs = el.runtimeStyle, - widths = me.styleInfos.borderImageInfo.getProps().widths; - - // Force border-style to solid so it doesn't collapse - rs.borderStyle = 'solid'; - - // If widths specified in border-image shorthand, override border-width - // NOTE px units needed here as this gets used by the IE9 renderer too - if ( widths ) { - rs.borderTopWidth = widths['t'].pixels( el ) + 'px'; - rs.borderRightWidth = widths['r'].pixels( el ) + 'px'; - rs.borderBottomWidth = widths['b'].pixels( el ) + 'px'; - rs.borderLeftWidth = widths['l'].pixels( el ) + 'px'; - } - - // Make the border transparent - me.hideBorder(); - } - }, - - destroy: function() { - var me = this, - rs = me.targetElement.runtimeStyle; - rs.borderStyle = ''; - if (me.finalized || !me.styleInfos.borderInfo.isActive()) { - rs.borderColor = rs.borderWidth = ''; - } - PIE.RendererBase.destroy.call( this ); - } - -} ); -/** - * Renderer for outset box-shadows - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( { - - boxZIndex: 1, - boxName: 'outset-box-shadow', - - needsUpdate: function() { - var si = this.styleInfos; - return si.boxShadowInfo.changed() || si.borderRadiusInfo.changed(); - }, - - isActive: function() { - var boxShadowInfo = this.styleInfos.boxShadowInfo; - return boxShadowInfo.isActive() && boxShadowInfo.getProps().outset[0]; - }, - - draw: function() { - var me = this, - el = this.targetElement, - box = this.getBox(), - styleInfos = this.styleInfos, - shadowInfos = styleInfos.boxShadowInfo.getProps().outset, - radii = styleInfos.borderRadiusInfo.getProps(), - len = shadowInfos.length, - i = len, j, - bounds = this.boundsInfo.getBounds(), - w = bounds.w, - h = bounds.h, - clipAdjust = PIE.ieVersion === 8 ? 1 : 0, //workaround for IE8 bug where VML leaks out top/left of clip region by 1px - corners = [ 'tl', 'tr', 'br', 'bl' ], corner, - shadowInfo, shape, fill, ss, xOff, yOff, spread, blur, shrink, color, alpha, path, - totalW, totalH, focusX, focusY, isBottom, isRight; - - - function getShadowShape( index, corner, xOff, yOff, color, blur, path ) { - var shape = me.getShape( 'shadow' + index + corner, 'fill', box, len - index ), - fill = shape.fill; - - // Position and size - shape['coordsize'] = w * 2 + ',' + h * 2; - shape['coordorigin'] = '1,1'; - - // Color and opacity - shape['stroked'] = false; - shape['filled'] = true; - fill.color = color.colorValue( el ); - if( blur ) { - fill['type'] = 'gradienttitle'; //makes the VML gradient follow the shape's outline - hooray for undocumented features?!?! - fill['color2'] = fill.color; - fill['opacity'] = 0; - } - - // Path - shape.path = path; - - // This needs to go last for some reason, to prevent rendering at incorrect size - ss = shape.style; - ss.left = xOff; - ss.top = yOff; - ss.width = w; - ss.height = h; - - return shape; - } - - - while( i-- ) { - shadowInfo = shadowInfos[ i ]; - xOff = shadowInfo.xOffset.pixels( el ); - yOff = shadowInfo.yOffset.pixels( el ); - spread = shadowInfo.spread.pixels( el ); - blur = shadowInfo.blur.pixels( el ); - color = shadowInfo.color; - // Shape path - shrink = -spread - blur; - if( !radii && blur ) { - // If blurring, use a non-null border radius info object so that getBoxPath will - // round the corners of the expanded shadow shape rather than squaring them off. - radii = PIE.BorderRadiusStyleInfo.ALL_ZERO; - } - path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii ); - - if( blur ) { - totalW = ( spread + blur ) * 2 + w; - totalH = ( spread + blur ) * 2 + h; - focusX = totalW ? blur * 2 / totalW : 0; - focusY = totalH ? blur * 2 / totalH : 0; - if( blur - spread > w / 2 || blur - spread > h / 2 ) { - // If the blur is larger than half the element's narrowest dimension, we cannot do - // this with a single shape gradient, because its focussize would have to be less than - // zero which results in ugly artifacts. Instead we create four shapes, each with its - // gradient focus past center, and then clip them so each only shows the quadrant - // opposite the focus. - for( j = 4; j--; ) { - corner = corners[j]; - isBottom = corner.charAt( 0 ) === 'b'; - isRight = corner.charAt( 1 ) === 'r'; - shape = getShadowShape( i, corner, xOff, yOff, color, blur, path ); - fill = shape.fill; - fill['focusposition'] = ( isRight ? 1 - focusX : focusX ) + ',' + - ( isBottom ? 1 - focusY : focusY ); - fill['focussize'] = '0,0'; - - // Clip to show only the appropriate quadrant. Add 1px to the top/left clip values - // in IE8 to prevent a bug where IE8 displays one pixel outside the clip region. - shape.style.clip = 'rect(' + ( ( isBottom ? totalH / 2 : 0 ) + clipAdjust ) + 'px,' + - ( isRight ? totalW : totalW / 2 ) + 'px,' + - ( isBottom ? totalH : totalH / 2 ) + 'px,' + - ( ( isRight ? totalW / 2 : 0 ) + clipAdjust ) + 'px)'; - } - } else { - // TODO delete old quadrant shapes if resizing expands past the barrier - shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); - fill = shape.fill; - fill['focusposition'] = focusX + ',' + focusY; - fill['focussize'] = ( 1 - focusX * 2 ) + ',' + ( 1 - focusY * 2 ); - } - } else { - shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); - alpha = color.alpha(); - if( alpha < 1 ) { - // shape.style.filter = 'alpha(opacity=' + ( alpha * 100 ) + ')'; - // ss.filter = 'progid:DXImageTransform.Microsoft.BasicImage(opacity=' + ( alpha ) + ')'; - shape.fill.opacity = alpha; - } - } - } - } - -} ); -/** - * Renderer for re-rendering img elements using VML. Kicks in if the img has - * a border-radius applied, or if the -pie-png-fix flag is set. - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.ImgRenderer = PIE.RendererBase.newRenderer( { - - boxZIndex: 6, - boxName: 'imgEl', - - needsUpdate: function() { - var si = this.styleInfos; - return this.targetElement.src !== this._lastSrc || si.borderRadiusInfo.changed(); - }, - - isActive: function() { - var si = this.styleInfos; - return si.borderRadiusInfo.isActive() || si.backgroundInfo.isPngFix(); - }, - - draw: function() { - this._lastSrc = src; - this.hideActualImg(); - - var shape = this.getShape( 'img', 'fill', this.getBox() ), - fill = shape.fill, - bounds = this.boundsInfo.getBounds(), - w = bounds.w, - h = bounds.h, - borderProps = this.styleInfos.borderInfo.getProps(), - borderWidths = borderProps && borderProps.widths, - el = this.targetElement, - src = el.src, - round = Math.round, - cs = el.currentStyle, - getLength = PIE.getLength, - s, zero; - - // In IE6, the BorderRenderer will have hidden the border by moving the border-width to - // the padding; therefore we want to pretend the borders have no width so they aren't doubled - // when adding in the current padding value below. - if( !borderWidths || PIE.ieVersion < 7 ) { - zero = PIE.getLength( '0' ); - borderWidths = { 't': zero, 'r': zero, 'b': zero, 'l': zero }; - } - - shape.stroked = false; - fill.type = 'frame'; - fill.src = src; - fill.position = (w ? 0.5 / w : 0) + ',' + (h ? 0.5 / h : 0); - shape.coordsize = w * 2 + ',' + h * 2; - shape.coordorigin = '1,1'; - shape.path = this.getBoxPath( { - t: round( borderWidths['t'].pixels( el ) + getLength( cs.paddingTop ).pixels( el ) ), - r: round( borderWidths['r'].pixels( el ) + getLength( cs.paddingRight ).pixels( el ) ), - b: round( borderWidths['b'].pixels( el ) + getLength( cs.paddingBottom ).pixels( el ) ), - l: round( borderWidths['l'].pixels( el ) + getLength( cs.paddingLeft ).pixels( el ) ) - }, 2 ); - s = shape.style; - s.width = w; - s.height = h; - }, - - hideActualImg: function() { - this.targetElement.runtimeStyle.filter = 'alpha(opacity=0)'; - }, - - destroy: function() { - PIE.RendererBase.destroy.call( this ); - this.targetElement.runtimeStyle.filter = ''; - } - -} ); -/** - * Root renderer for IE9; manages the rendering layers in the element's background - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - */ -PIE.IE9RootRenderer = PIE.RendererBase.newRenderer( { - - updatePos: PIE.emptyFn, - updateSize: PIE.emptyFn, - updateVisibility: PIE.emptyFn, - updateProps: PIE.emptyFn, - - outerCommasRE: /^,+|,+$/g, - innerCommasRE: /,+/g, - - setBackgroundLayer: function(zIndex, bg) { - var me = this, - bgLayers = me._bgLayers || ( me._bgLayers = [] ), - undef; - bgLayers[zIndex] = bg || undef; - }, - - finishUpdate: function() { - var me = this, - bgLayers = me._bgLayers, - bg; - if( bgLayers && ( bg = bgLayers.join( ',' ).replace( me.outerCommasRE, '' ).replace( me.innerCommasRE, ',' ) ) !== me._lastBg ) { - me._lastBg = me.targetElement.runtimeStyle.background = bg; - } - }, - - destroy: function() { - this.targetElement.runtimeStyle.background = ''; - delete this._bgLayers; - } - -} ); -/** - * Renderer for element backgrounds, specific for IE9. Only handles translating CSS3 gradients - * to an equivalent SVG data URI. - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - */ -PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( { - - bgLayerZIndex: 1, - - needsUpdate: function() { - var si = this.styleInfos; - return si.backgroundInfo.changed(); - }, - - isActive: function() { - var si = this.styleInfos; - return si.backgroundInfo.isActive() || si.borderImageInfo.isActive(); - }, - - draw: function() { - var me = this, - props = me.styleInfos.backgroundInfo.getProps(), - bg, images, i = 0, img, bgAreaSize, bgSize; - - if ( props ) { - bg = []; - - images = props.bgImages; - if ( images ) { - while( img = images[ i++ ] ) { - if (img.imgType === 'linear-gradient' ) { - bgAreaSize = me.getBgAreaSize( img.bgOrigin ); - bgSize = ( img.bgSize || PIE.BgSize.DEFAULT ).pixels( - me.targetElement, bgAreaSize.w, bgAreaSize.h, bgAreaSize.w, bgAreaSize.h - ), - bg.push( - 'url(data:image/svg+xml,' + escape( me.getGradientSvg( img, bgSize.w, bgSize.h ) ) + ') ' + - me.bgPositionToString( img.bgPosition ) + ' / ' + bgSize.w + 'px ' + bgSize.h + 'px ' + - ( img.bgAttachment || '' ) + ' ' + ( img.bgOrigin || '' ) + ' ' + ( img.bgClip || '' ) - ); - } else { - bg.push( img.origString ); - } - } - } - - if ( props.color ) { - bg.push( props.color.val ); - } - - me.parent.setBackgroundLayer(me.bgLayerZIndex, bg.join(',')); - } - }, - - bgPositionToString: function( bgPosition ) { - return bgPosition ? bgPosition.tokens.map(function(token) { - return token.tokenValue; - }).join(' ') : '0 0'; - }, - - getBgAreaSize: function( bgOrigin ) { - var me = this, - el = me.targetElement, - bounds = me.boundsInfo.getBounds(), - elW = bounds.w, - elH = bounds.h, - w = elW, - h = elH, - borders, getLength, cs; - - if( bgOrigin !== 'border-box' ) { - borders = me.styleInfos.borderInfo.getProps(); - if( borders && ( borders = borders.widths ) ) { - w -= borders[ 'l' ].pixels( el ) + borders[ 'l' ].pixels( el ); - h -= borders[ 't' ].pixels( el ) + borders[ 'b' ].pixels( el ); - } - } - - if ( bgOrigin === 'content-box' ) { - getLength = PIE.getLength; - cs = el.currentStyle; - w -= getLength( cs.paddingLeft ).pixels( el ) + getLength( cs.paddingRight ).pixels( el ); - h -= getLength( cs.paddingTop ).pixels( el ) + getLength( cs.paddingBottom ).pixels( el ); - } - - return { w: w, h: h }; - }, - - getGradientSvg: function( info, bgWidth, bgHeight ) { - var el = this.targetElement, - stopsInfo = info.stops, - stopCount = stopsInfo.length, - metrics = PIE.GradientUtil.getGradientMetrics( el, bgWidth, bgHeight, info ), - startX = metrics.startX, - startY = metrics.startY, - endX = metrics.endX, - endY = metrics.endY, - lineLength = metrics.lineLength, - stopPx, - i, j, before, after, - svg; - - // Find the pixel offsets along the CSS3 gradient-line for each stop. - stopPx = []; - for( i = 0; i < stopCount; i++ ) { - stopPx.push( stopsInfo[i].offset ? stopsInfo[i].offset.pixels( el, lineLength ) : - i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); - } - // Fill in gaps with evenly-spaced offsets - for( i = 1; i < stopCount; i++ ) { - if( stopPx[ i ] === null ) { - before = stopPx[ i - 1 ]; - j = i; - do { - after = stopPx[ ++j ]; - } while( after === null ); - stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); - } - } - - svg = [ - '' + - '' + - '' - ]; - - // Convert to percentage along the SVG gradient line and add to the stops list - for( i = 0; i < stopCount; i++ ) { - svg.push( - '' - ); - } - - svg.push( - '' + - '' + - '' + - '' - ); - - return svg.join( '' ); - }, - - destroy: function() { - this.parent.setBackgroundLayer( this.bgLayerZIndex ); - } - -} ); -/** - * Renderer for border-image - * @constructor - * @param {Element} el The target element - * @param {Object} styleInfos The StyleInfo objects - * @param {PIE.RootRenderer} parent - */ -PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( { - - REPEAT: 'repeat', - STRETCH: 'stretch', - ROUND: 'round', - - bgLayerZIndex: 0, - - needsUpdate: function() { - return this.styleInfos.borderImageInfo.changed(); - }, - - isActive: function() { - return this.styleInfos.borderImageInfo.isActive(); - }, - - draw: function() { - var me = this, - props = me.styleInfos.borderImageInfo.getProps(), - borderProps = me.styleInfos.borderInfo.getProps(), - bounds = me.boundsInfo.getBounds(), - repeat = props.repeat, - repeatH = repeat.h, - repeatV = repeat.v, - el = me.targetElement, - isAsync = 0; - - PIE.Util.withImageSize( props.src, function( imgSize ) { - var elW = bounds.w, - elH = bounds.h, - imgW = imgSize.w, - imgH = imgSize.h, - - // The image cannot be referenced as a URL directly in the SVG because IE9 throws a strange - // security exception (perhaps due to cross-origin policy within data URIs?) Therefore we - // work around this by converting the image data into a data URI itself using a transient - // canvas. This unfortunately requires the border-image src to be within the same domain, - // which isn't a limitation in true border-image, so we need to try and find a better fix. - imgSrc = me.imageToDataURI( props.src, imgW, imgH ), - - REPEAT = me.REPEAT, - STRETCH = me.STRETCH, - ROUND = me.ROUND, - ceil = Math.ceil, - - zero = PIE.getLength( '0' ), - widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), - widthT = widths['t'].pixels( el ), - widthR = widths['r'].pixels( el ), - widthB = widths['b'].pixels( el ), - widthL = widths['l'].pixels( el ), - slices = props.slice, - sliceT = slices['t'].pixels( el ), - sliceR = slices['r'].pixels( el ), - sliceB = slices['b'].pixels( el ), - sliceL = slices['l'].pixels( el ), - centerW = elW - widthL - widthR, - middleH = elH - widthT - widthB, - imgCenterW = imgW - sliceL - sliceR, - imgMiddleH = imgH - sliceT - sliceB, - - // Determine the size of each tile - 'round' is handled below - tileSizeT = repeatH === STRETCH ? centerW : imgCenterW * widthT / sliceT, - tileSizeR = repeatV === STRETCH ? middleH : imgMiddleH * widthR / sliceR, - tileSizeB = repeatH === STRETCH ? centerW : imgCenterW * widthB / sliceB, - tileSizeL = repeatV === STRETCH ? middleH : imgMiddleH * widthL / sliceL, - - svg, - patterns = [], - rects = [], - i = 0; - - // For 'round', subtract from each tile's size enough so that they fill the space a whole number of times - if (repeatH === ROUND) { - tileSizeT -= (tileSizeT - (centerW % tileSizeT || tileSizeT)) / ceil(centerW / tileSizeT); - tileSizeB -= (tileSizeB - (centerW % tileSizeB || tileSizeB)) / ceil(centerW / tileSizeB); - } - if (repeatV === ROUND) { - tileSizeR -= (tileSizeR - (middleH % tileSizeR || tileSizeR)) / ceil(middleH / tileSizeR); - tileSizeL -= (tileSizeL - (middleH % tileSizeL || tileSizeL)) / ceil(middleH / tileSizeL); - } - - - // Build the SVG for the border-image rendering. Add each piece as a pattern, which is then stretched - // or repeated as the fill of a rect of appropriate size. - svg = [ - '' - ]; - - function addImage( x, y, w, h, cropX, cropY, cropW, cropH, tileW, tileH ) { - patterns.push( - '' + - '' + - '' + - '' + - '' - ); - rects.push( - '' - ); - i++; - } - addImage( 0, 0, widthL, widthT, 0, 0, sliceL, sliceT, widthL, widthT ); // top left - addImage( widthL, 0, centerW, widthT, sliceL, 0, imgCenterW, sliceT, tileSizeT, widthT ); // top center - addImage( elW - widthR, 0, widthR, widthT, imgW - sliceR, 0, sliceR, sliceT, widthR, widthT ); // top right - addImage( 0, widthT, widthL, middleH, 0, sliceT, sliceL, imgMiddleH, widthL, tileSizeL ); // middle left - if ( props.fill ) { // center fill - addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH, - tileSizeT || tileSizeB || imgCenterW, tileSizeL || tileSizeR || imgMiddleH ); - } - addImage( elW - widthR, widthT, widthR, middleH, imgW - sliceR, sliceT, sliceR, imgMiddleH, widthR, tileSizeR ); // middle right - addImage( 0, elH - widthB, widthL, widthB, 0, imgH - sliceB, sliceL, sliceB, widthL, widthB ); // bottom left - addImage( widthL, elH - widthB, centerW, widthB, sliceL, imgH - sliceB, imgCenterW, sliceB, tileSizeB, widthB ); // bottom center - addImage( elW - widthR, elH - widthB, widthR, widthB, imgW - sliceR, imgH - sliceB, sliceR, sliceB, widthR, widthB ); // bottom right - - svg.push( - '' + - patterns.join('\n') + - '' + - rects.join('\n') + - '' - ); - - me.parent.setBackgroundLayer( me.bgLayerZIndex, 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box' ); - - // If the border-image's src wasn't immediately available, the SVG for its background layer - // will have been created asynchronously after the main element's update has finished; we'll - // therefore need to force the root renderer to sync to the final background once finished. - if( isAsync ) { - me.parent.finishUpdate(); - } - }, me ); - - isAsync = 1; - }, - - /** - * Convert a given image to a data URI - */ - imageToDataURI: (function() { - var uris = {}; - return function( src, width, height ) { - var uri = uris[ src ], - image, canvas; - if ( !uri ) { - image = new Image(); - canvas = doc.createElement( 'canvas' ); - image.src = src; - canvas.width = width; - canvas.height = height; - canvas.getContext( '2d' ).drawImage( image, 0, 0 ); - uri = uris[ src ] = canvas.toDataURL(); - } - return uri; - } - })(), - - prepareUpdate: PIE.BorderImageRenderer.prototype.prepareUpdate, - - destroy: function() { - var me = this, - rs = me.targetElement.runtimeStyle; - me.parent.setBackgroundLayer( me.bgLayerZIndex ); - rs.borderColor = rs.borderStyle = rs.borderWidth = ''; - } - -} ); - -PIE.Element = (function() { - - var wrappers = {}, - lazyInitCssProp = PIE.CSS_PREFIX + 'lazy-init', - pollCssProp = PIE.CSS_PREFIX + 'poll', - trackActiveCssProp = PIE.CSS_PREFIX + 'track-active', - trackHoverCssProp = PIE.CSS_PREFIX + 'track-hover', - hoverClass = PIE.CLASS_PREFIX + 'hover', - activeClass = PIE.CLASS_PREFIX + 'active', - focusClass = PIE.CLASS_PREFIX + 'focus', - firstChildClass = PIE.CLASS_PREFIX + 'first-child', - ignorePropertyNames = { 'background':1, 'bgColor':1, 'display': 1 }, - classNameRegExes = {}, - dummyArray = []; - - - function addClass( el, className ) { - el.className += ' ' + className; - } - - function removeClass( el, className ) { - var re = classNameRegExes[ className ] || - ( classNameRegExes[ className ] = new RegExp( '\\b' + className + '\\b', 'g' ) ); - el.className = el.className.replace( re, '' ); - } - - function delayAddClass( el, className /*, className2*/ ) { - var classes = dummyArray.slice.call( arguments, 1 ), - i = classes.length; - setTimeout( function() { - if( el ) { - while( i-- ) { - addClass( el, classes[ i ] ); - } - } - }, 0 ); - } - - function delayRemoveClass( el, className /*, className2*/ ) { - var classes = dummyArray.slice.call( arguments, 1 ), - i = classes.length; - setTimeout( function() { - if( el ) { - while( i-- ) { - removeClass( el, classes[ i ] ); - } - } - }, 0 ); - } - - - - function Element( el ) { - var renderers, - rootRenderer, - boundsInfo = new PIE.BoundsInfo( el ), - styleInfos, - styleInfosArr, - initializing, - initialized, - eventsAttached, - eventListeners = [], - delayed, - destroyed, - poll; - - /** - * Initialize PIE for this element. - */ - function init() { - if( !initialized ) { - var docEl, - bounds, - ieDocMode = PIE.ieDocMode, - cs = el.currentStyle, - lazy = cs.getAttribute( lazyInitCssProp ) === 'true', - trackActive = cs.getAttribute( trackActiveCssProp ) !== 'false', - trackHover = cs.getAttribute( trackHoverCssProp ) !== 'false', - childRenderers; - - // Polling for size/position changes: default to on in IE8, off otherwise, overridable by -pie-poll - poll = cs.getAttribute( pollCssProp ); - poll = ieDocMode > 7 ? poll !== 'false' : poll === 'true'; - - // Force layout so move/resize events will fire. Set this as soon as possible to avoid layout changes - // after load, but make sure it only gets called the first time through to avoid recursive calls to init(). - if( !initializing ) { - initializing = 1; - el.runtimeStyle.zoom = 1; - initFirstChildPseudoClass(); - } - - boundsInfo.lock(); - - // If the -pie-lazy-init:true flag is set, check if the element is outside the viewport and if so, delay initialization - if( lazy && ( bounds = boundsInfo.getBounds() ) && ( docEl = doc.documentElement || doc.body ) && - ( bounds.y > docEl.clientHeight || bounds.x > docEl.clientWidth || bounds.y + bounds.h < 0 || bounds.x + bounds.w < 0 ) ) { - if( !delayed ) { - delayed = 1; - PIE.OnScroll.observe( init ); - } - } else { - initialized = 1; - delayed = initializing = 0; - PIE.OnScroll.unobserve( init ); - - // Create the style infos and renderers - if ( ieDocMode === 9 ) { - styleInfos = { - backgroundInfo: new PIE.BackgroundStyleInfo( el ), - borderImageInfo: new PIE.BorderImageStyleInfo( el ), - borderInfo: new PIE.BorderStyleInfo( el ) - }; - styleInfosArr = [ - styleInfos.backgroundInfo, - styleInfos.borderImageInfo - ]; - rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); - childRenderers = [ - new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) - ]; - } else { - - styleInfos = { - backgroundInfo: new PIE.BackgroundStyleInfo( el ), - borderInfo: new PIE.BorderStyleInfo( el ), - borderImageInfo: new PIE.BorderImageStyleInfo( el ), - borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), - boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), - visibilityInfo: new PIE.VisibilityStyleInfo( el ) - }; - styleInfosArr = [ - styleInfos.backgroundInfo, - styleInfos.borderInfo, - styleInfos.borderImageInfo, - styleInfos.borderRadiusInfo, - styleInfos.boxShadowInfo, - styleInfos.visibilityInfo - ]; - rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); - childRenderers = [ - new PIE.BoxShadowOutsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), - //new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ), - new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) - ]; - if( el.tagName === 'IMG' ) { - childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) ); - } - rootRenderer.childRenderers = childRenderers; // circular reference, can't pass in constructor; TODO is there a cleaner way? - } - renderers = [ rootRenderer ].concat( childRenderers ); - - // Add property change listeners to ancestors if requested - initAncestorEventListeners(); - - // Add to list of polled elements in IE8 - if( poll ) { - PIE.Heartbeat.observe( update ); - PIE.Heartbeat.run(); - } - - // Trigger rendering - update( 1 ); - } - - if( !eventsAttached ) { - eventsAttached = 1; - if( ieDocMode < 9 ) { - addListener( el, 'onmove', handleMoveOrResize ); - } - addListener( el, 'onresize', handleMoveOrResize ); - addListener( el, 'onpropertychange', propChanged ); - if( trackHover ) { - addListener( el, 'onmouseenter', mouseEntered ); - } - if( trackHover || trackActive ) { - addListener( el, 'onmouseleave', mouseLeft ); - } - if( trackActive ) { - addListener( el, 'onmousedown', mousePressed ); - } - if( el.tagName in PIE.focusableElements ) { - addListener( el, 'onfocus', focused ); - addListener( el, 'onblur', blurred ); - } - PIE.OnResize.observe( handleMoveOrResize ); - - PIE.OnUnload.observe( removeEventListeners ); - } - - boundsInfo.unlock(); - } - } - - - - - /** - * Event handler for onmove and onresize events. Invokes update() only if the element's - * bounds have previously been calculated, to prevent multiple runs during page load when - * the element has no initial CSS3 properties. - */ - function handleMoveOrResize() { - if( boundsInfo && boundsInfo.hasBeenQueried() ) { - update(); - } - } - - - /** - * Update position and/or size as necessary. Both move and resize events call - * this rather than the updatePos/Size functions because sometimes, particularly - * during page load, one will fire but the other won't. - */ - function update( force ) { - if( !destroyed ) { - if( initialized ) { - var i, len = renderers.length; - - lockAll(); - for( i = 0; i < len; i++ ) { - renderers[i].prepareUpdate(); - } - if( force || boundsInfo.positionChanged() ) { - /* TODO just using getBoundingClientRect (used internally by BoundsInfo) for detecting - position changes may not always be accurate; it's possible that - an element will actually move relative to its positioning parent, but its position - relative to the viewport will stay the same. Need to come up with a better way to - track movement. The most accurate would be the same logic used in RootRenderer.updatePos() - but that is a more expensive operation since it does some DOM walking, and we want this - check to be as fast as possible. */ - for( i = 0; i < len; i++ ) { - renderers[i].updatePos(); - } - } - if( force || boundsInfo.sizeChanged() ) { - for( i = 0; i < len; i++ ) { - renderers[i].updateSize(); - } - } - rootRenderer.finishUpdate(); - unlockAll(); - } - else if( !initializing ) { - init(); - } - } - } - - /** - * Handle property changes to trigger update when appropriate. - */ - function propChanged() { - var i, len = renderers.length, - renderer, - e = event; - - // Some elements like fire onpropertychange events for old-school background properties - // ('background', 'bgColor') when runtimeStyle background properties are changed, which - // results in an infinite loop; therefore we filter out those property names. Also, 'display' - // is ignored because size calculations don't work correctly immediately when its onpropertychange - // event fires, and because it will trigger an onresize event anyway. - if( !destroyed && !( e && e.propertyName in ignorePropertyNames ) ) { - if( initialized ) { - lockAll(); - for( i = 0; i < len; i++ ) { - renderers[i].prepareUpdate(); - } - for( i = 0; i < len; i++ ) { - renderer = renderers[i]; - // Make sure position is synced if the element hasn't already been rendered. - // TODO this feels sloppy - look into merging propChanged and update functions - if( !renderer.isPositioned ) { - renderer.updatePos(); - } - if( renderer.needsUpdate() ) { - renderer.updateProps(); - } - } - rootRenderer.finishUpdate(); - unlockAll(); - } - else if( !initializing ) { - init(); - } - } - } - - - /** - * Handle mouseenter events. Adds a custom class to the element to allow IE6 to add - * hover styles to non-link elements, and to trigger a propertychange update. - */ - function mouseEntered() { - //must delay this because the mouseenter event fires before the :hover styles are added. - delayAddClass( el, hoverClass ); - } - - /** - * Handle mouseleave events - */ - function mouseLeft() { - //must delay this because the mouseleave event fires before the :hover styles are removed. - delayRemoveClass( el, hoverClass, activeClass ); - } - - /** - * Handle mousedown events. Adds a custom class to the element to allow IE6 to add - * active styles to non-link elements, and to trigger a propertychange update. - */ - function mousePressed() { - //must delay this because the mousedown event fires before the :active styles are added. - delayAddClass( el, activeClass ); - - // listen for mouseups on the document; can't just be on the element because the user might - // have dragged out of the element while the mouse button was held down - PIE.OnMouseup.observe( mouseReleased ); - } - - /** - * Handle mouseup events - */ - function mouseReleased() { - //must delay this because the mouseup event fires before the :active styles are removed. - delayRemoveClass( el, activeClass ); - - PIE.OnMouseup.unobserve( mouseReleased ); - } - - /** - * Handle focus events. Adds a custom class to the element to trigger a propertychange update. - */ - function focused() { - //must delay this because the focus event fires before the :focus styles are added. - delayAddClass( el, focusClass ); - } - - /** - * Handle blur events - */ - function blurred() { - //must delay this because the blur event fires before the :focus styles are removed. - delayRemoveClass( el, focusClass ); - } - - - /** - * Handle property changes on ancestors of the element; see initAncestorEventListeners() - * which adds these listeners as requested with the -pie-watch-ancestors CSS property. - */ - function ancestorPropChanged() { - var name = event.propertyName; - if( name === 'className' || name === 'id' ) { - propChanged(); - } - } - - function lockAll() { - boundsInfo.lock(); - for( var i = styleInfosArr.length; i--; ) { - styleInfosArr[i].lock(); - } - } - - function unlockAll() { - for( var i = styleInfosArr.length; i--; ) { - styleInfosArr[i].unlock(); - } - boundsInfo.unlock(); - } - - - function addListener( targetEl, type, handler ) { - targetEl.attachEvent( type, handler ); - eventListeners.push( [ targetEl, type, handler ] ); - } - - /** - * Remove all event listeners from the element and any monitored ancestors. - */ - function removeEventListeners() { - if (eventsAttached) { - var i = eventListeners.length, - listener; - - while( i-- ) { - listener = eventListeners[ i ]; - listener[ 0 ].detachEvent( listener[ 1 ], listener[ 2 ] ); - } - - PIE.OnUnload.unobserve( removeEventListeners ); - eventsAttached = 0; - eventListeners = []; - } - } - - - /** - * Clean everything up when the behavior is removed from the element, or the element - * is manually destroyed. - */ - function destroy() { - if( !destroyed ) { - var i, len; - - removeEventListeners(); - - destroyed = 1; - - // destroy any active renderers - if( renderers ) { - for( i = 0, len = renderers.length; i < len; i++ ) { - renderers[i].finalized = 1; - renderers[i].destroy(); - } - } - - // Remove from list of polled elements in IE8 - if( poll ) { - PIE.Heartbeat.unobserve( update ); - } - // Stop onresize listening - PIE.OnResize.unobserve( update ); - - // Kill references - renderers = boundsInfo = styleInfos = styleInfosArr = el = null; - } - } - - - /** - * If requested via the custom -pie-watch-ancestors CSS property, add onpropertychange and - * other event listeners to ancestor(s) of the element so we can pick up style changes - * based on CSS rules using descendant selectors. - */ - function initAncestorEventListeners() { - var watch = el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'watch-ancestors' ), - i, a; - if( watch ) { - watch = parseInt( watch, 10 ); - i = 0; - a = el.parentNode; - while( a && ( watch === 'NaN' || i++ < watch ) ) { - addListener( a, 'onpropertychange', ancestorPropChanged ); - addListener( a, 'onmouseenter', mouseEntered ); - addListener( a, 'onmouseleave', mouseLeft ); - addListener( a, 'onmousedown', mousePressed ); - if( a.tagName in PIE.focusableElements ) { - addListener( a, 'onfocus', focused ); - addListener( a, 'onblur', blurred ); - } - a = a.parentNode; - } - } - } - - - /** - * If the target element is a first child, add a pie_first-child class to it. This allows using - * the added class as a workaround for the fact that PIE's rendering element breaks the :first-child - * pseudo-class selector. - */ - function initFirstChildPseudoClass() { - var tmpEl = el, - isFirst = 1; - while( tmpEl = tmpEl.previousSibling ) { - if( tmpEl.nodeType === 1 ) { - isFirst = 0; - break; - } - } - if( isFirst ) { - addClass( el, firstChildClass ); - } - } - - - // These methods are all already bound to this instance so there's no need to wrap them - // in a closure to maintain the 'this' scope object when calling them. - this.init = init; - this.update = update; - this.destroy = destroy; - this.el = el; - } - - Element.getInstance = function( el ) { - var id = PIE.Util.getUID( el ); - return wrappers[ id ] || ( wrappers[ id ] = new Element( el ) ); - }; - - Element.destroy = function( el ) { - var id = PIE.Util.getUID( el ), - wrapper = wrappers[ id ]; - if( wrapper ) { - wrapper.destroy(); - delete wrappers[ id ]; - } - }; - - Element.destroyAll = function() { - var els = [], wrapper; - if( wrappers ) { - for( var w in wrappers ) { - if( wrappers.hasOwnProperty( w ) ) { - wrapper = wrappers[ w ]; - els.push( wrapper.el ); - wrapper.destroy(); - } - } - wrappers = {}; - } - return els; - }; - - return Element; -})(); - -/* - * This file exposes the public API for invoking PIE. - */ - - -/** - * @property supportsVML - * True if the current IE browser environment has a functioning VML engine. Should be true - * in most IEs, but in rare cases may be false. If false, PIE will exit immediately when - * attached to an element; this property may be used for debugging or by external scripts - * to perform some special action when VML support is absent. - * @type {boolean} - */ -PIE[ 'supportsVML' ] = PIE.supportsVML; - - -/** - * Programatically attach PIE to a single element. - * @param {Element} el - */ -PIE[ 'attach' ] = function( el ) { - if (PIE.ieDocMode < 10 && PIE.supportsVML) { - PIE.Element.getInstance( el ).init(); - } -}; - - -/** - * Programatically detach PIE from a single element. - * @param {Element} el - */ -PIE[ 'detach' ] = function( el ) { - PIE.Element.destroy( el ); -}; - - -} // if( !PIE ) -})(); \ No newline at end of file diff --git a/client/client/src/assets/sound_crossed.png b/client/client/src/assets/sound_crossed.png deleted file mode 100644 index 65d3c45f..00000000 Binary files a/client/client/src/assets/sound_crossed.png and /dev/null differ diff --git a/client/client/src/assets/speaker.png b/client/client/src/assets/speaker.png deleted file mode 100644 index 7cc07b4b..00000000 Binary files a/client/client/src/assets/speaker.png and /dev/null differ diff --git a/client/client/src/assets/transfer.png b/client/client/src/assets/transfer.png deleted file mode 100644 index 31f7fd3a..00000000 Binary files a/client/client/src/assets/transfer.png and /dev/null differ diff --git a/client/client/src/assets/unhold.png b/client/client/src/assets/unhold.png deleted file mode 100644 index 0846555d..00000000 Binary files a/client/client/src/assets/unhold.png and /dev/null differ diff --git a/client/client/src/com/flashphoner/phone/APINotifyPhone.as b/client/client/src/com/flashphoner/phone/APINotifyPhone.as deleted file mode 100644 index 39aa7a0a..00000000 --- a/client/client/src/com/flashphoner/phone/APINotifyPhone.as +++ /dev/null @@ -1,154 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.phone -{ - import com.flashphoner.api.Call; - import com.flashphoner.api.Flash_API; - import com.flashphoner.api.data.ErrorCodes; - import com.flashphoner.api.data.PhoneConfig; - import com.flashphoner.api.interfaces.APINotify; - - import mx.controls.Alert; - import mx.core.Application; - import mx.messaging.errors.MessagingError; - import mx.messaging.errors.NoChannelAvailableError; - import mx.utils.object_proxy; - - /** - * Implementation APINotify for handler events - * Example: flash_API.addAPINotify(new APINotifyPhone()) - **/ - public class APINotifyPhone implements APINotify - { - public function APINotifyPhone() - { - } - public function notifyCloseConnection():void{ - DataPhone.getInstance().viewController.closedConnectingView(); - phone(Application.application).toLoggedOffState(); - phone(Application.application).videoView.stopVideo(); - phone(Application.application).videoView.onCloseClick(); - DataPhone.getInstance().viewController.hideIncomingView(); - } - public function notifyConnected():void{ - if (!PhoneConfig.REGISTER_REQUIRED){ - DataPhone.getInstance().sipAccountView.close(); - phone(Application.application).toLoggedState(); - DataPhone.getInstance().viewController.hideConnectingView(); - } else { - DataPhone.getInstance().viewController.waitingForRegisteredConnectionView(); - } - } - public function notifyRegistered(_sipObject:Object):void{ - if (PhoneConfig.REGISTER_REQUIRED){ - DataPhone.getInstance().sipAccountView.close(); - phone(Application.application).toLoggedState(); - DataPhone.getInstance().viewController.hideConnectingView(); - } - - } - public function notifyBalance(balance:Number,_sipObject:Object):void{ - - } - - public function notifyBugReport(filename:String):void{ - } - - public function notify(call:Call,_sipObject:Object):void{ - if (call.state == Call.STATE_FINISH){ - DataPhone.getInstance().viewController.hideIncomingView(); - phone(Application.application).videoView.onCloseClick(); - }else if (call.state == Call.STATE_HOLD){ - DataPhone.getInstance().getCallView(call.id).callHolded(); - }else if (call.state == Call.STATE_TALK){ - DataPhone.getInstance().getCallView(call.id).callUnholded(); - } - } - - public function notifyCallbackHold(call:Call,isHold:Boolean):void{ - DataPhone.getInstance().getCallView(call.id).iHolded(isHold); - } - - public function notifyCost(call:Call,cost:Number):void{ - - } - - public function notifyError(error:String,_sipObject:Object=null):void{ - if (error == ErrorCodes.CONNECTION_ERROR){ - DataPhone.getInstance().viewController.failConnectionView(); - } else - if (error == ErrorCodes.AUTHENTICATION_FAIL){ - DataPhone.getInstance().viewController.failRegisterView(); - } else - if (error == ErrorCodes.USER_NOT_AVAILABLE){ - DataPhone.getInstance().viewController.calleeNotFoundView(); - } else if (error==ErrorCodes.TOO_MANY_REGISTER_ATTEMPTS){ - mx.controls.Alert.show("Connection error"); - phone(Application.application).toLoggedOffState(); - } else if (error==ErrorCodes.LICENSE_RESTRICTION){ - mx.controls.Alert.show("License restriction:\n'Trial period has been expired' \nOR 'Too many connects'.\n Check the serial number."); - } else if (error==ErrorCodes.LICENSE_NOT_FOUND){ - mx.controls.Alert.show("Please set the license key.\nYou can get it here -\nwww.flashphoner.com/license."); - } else if (error==ErrorCodes.INTERNAL_SIP_ERROR){ - mx.controls.Alert.show("There is a SIP problem in \nFlashphoner side or your SIP-provider side.\nPlease send logs and other info\n to Flashphoner support team."); - } else if (error == ErrorCodes.REGISTER_EXPIRE){ - DataPhone.getInstance().viewController.registerAttemptExpire(); - } else if (error == ErrorCodes.SIP_PORTS_BUSY){ - DataPhone.getInstance().viewController.sipPortsBusyView(); - } else if (error == ErrorCodes.MEDIA_PORTS_BUSY){ - DataPhone.getInstance().viewController.mediaPortsBusyView(); - } else if (error == ErrorCodes.WRONG_SIPPROVIDER_ADDRESS){ - DataPhone.getInstance().viewController.wrongSipProviderAddressView(); - } - } - - public function notifyVideoFormat(videoFormat:Object,_sipObject:Object = null):void{ - } - - public function notifyOpenVideoView(isViewed:Boolean):void{ - if (isViewed){ - phone(Application.application).onOpenVideoView(); - }else{ - phone(Application.application).videoView.onCloseClick(); - } - } - - public function notifyMessage(messageObject:Object, notifyMessageResult:Object, sipObject:Object):void { - DataPhone.getInstance().viewController.pushMessageToInstantMessageChatView(messageObject); - } - - public function notifyAddCall(call:Call):void{ - if (call.incoming){ - DataPhone.getInstance().viewController.showIncomingView(call); - } - } - - public function notifyRemoveCall(call:Call):void{ - } - - public function notifySubscription(subscriptionObj:Object, sipObj:Object):void { - } - - public function addLogMessage(message:String):void{ - - } - - public function notifyVersion(version:String):void{ - DataPhone.getInstance().version = version; - } - - public function notifyXcapResponse(xcapResponse:String):void{ - - } - } -} diff --git a/client/client/src/com/flashphoner/phone/DataPhone.as b/client/client/src/com/flashphoner/phone/DataPhone.as deleted file mode 100644 index 0ecd6b82..00000000 --- a/client/client/src/com/flashphoner/phone/DataPhone.as +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.phone -{ - import com.flashphoner.api.Flash_API; - import com.flashphoner.phone.views.CallView; - import com.flashphoner.phone.views.IncomingView; - import com.flashphoner.phone.views.InstantMessageChatView; - import com.flashphoner.phone.views.MicrophoneSettingsView; - import com.flashphoner.phone.views.PhoneButton; - import com.flashphoner.phone.views.SipAccountView; - import com.flashphoner.phone.views.TabChatView; - import com.flashphoner.phone.views.TransferView; - - import flash.display.DisplayObject; - import flash.display.DisplayObjectContainer; - - import mx.collections.ArrayCollection; - import mx.controls.List; - - /** - * Data of phone widget - **/ - public class DataPhone - { - private static var data:DataPhone; - /** - * Get instance of a singelton - **/ - public static function getInstance():DataPhone{ - if (data == null){ - data = new DataPhone(); - data.flash_API = new Flash_API(new APINotifyPhone()); - data.version = data.flash_API.getVersion(); - } - return data; - } - - [Bindable] - public var version:String; - - /** - * Flash_API used for phone widget - **/ - public var flash_API:Flash_API; - - /** - * Controller of events - **/ - public var viewController:ViewControllerPhone = new ViewControllerPhone(); - - /** - * list of calls in phone - **/ - public var listCalls:List; - - /** - * Instance of incomming view - **/ - public var incommingView:IncomingView = new IncomingView(); - - /** - * Instance of transfer view - **/ - public var transferView:TransferView = new TransferView(); - - /** - * Instance of sip account view - **/ - public var sipAccountView:SipAccountView = new SipAccountView(); - - /** - * Instance of microphone settings view - **/ - public var microphoneSettingsView:MicrophoneSettingsView = new MicrophoneSettingsView(); - - public var tabChatView:TabChatView = new TabChatView(); - - /** - * Get object of CallView which corresponds call - * @param callId identifier of call - **/ - public function getCallView(callId:String):CallView{ - var index:Number = flash_API.getIndexByCallId(callId); - var obj:* = listCalls.indexToItemRenderer(index); - return obj as CallView; - - } - } -} diff --git a/client/client/src/com/flashphoner/phone/ViewControllerPhone.as b/client/client/src/com/flashphoner/phone/ViewControllerPhone.as deleted file mode 100644 index c5bc86a4..00000000 --- a/client/client/src/com/flashphoner/phone/ViewControllerPhone.as +++ /dev/null @@ -1,163 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.phone -{ - import com.flashphoner.Logger; - import com.flashphoner.api.Call; - import com.flashphoner.api.Flash_API; - import com.flashphoner.phone.views.ConnectingView; - - import flash.display.DisplayObject; - import flash.filters.BevelFilter; - import flash.utils.setTimeout; - - import mx.core.Application; - import mx.managers.PopUpManager; - - public class ViewControllerPhone - { - private var connectingView:ConnectingView; - - public function ViewControllerPhone() - { - } - - public function failRegisterView():void{ - if (connectingView!=null){ - Logger.info("PhoneView.failRegisterView()"); - connectingView.text="Register fail"; - setTimeout(disconnect,3000); - } - } - public function sipPortsBusyView():void{ - showConnectingView(); - if (connectingView!=null){ - Logger.info("PhoneView.sipPortsBusyView()"); - connectingView.text="All sip ports is busy"; - connectingView.beClosed = true; - setTimeout(disconnect,3000); - } - } - - public function wrongSipProviderAddressView():void{ - showConnectingView(); - if (connectingView!=null){ - Logger.info("PhoneView.wrongSipProviderAddressView()"); - connectingView.text="Wrong sip provider address"; - connectingView.beClosed = true; - setTimeout(disconnect,3000); - } - } - - public function waitingForRegisteredConnectionView():void{ - if (connectingView!=null && !connectingView.beClosed){ - Logger.info("PhoneView.waitingForRegisteredConnectionView()"); - connectingView.text="Waiting for registered event..."; - } - } - - public function hideConnectingView():void{ - if (connectingView!=null){ - PopUpManager.removePopUp(connectingView); - connectingView=null; - } - } - - public function showConnectingView():void{ - if (connectingView==null){ - connectingView = new ConnectingView(); - PopUpManager.addPopUp(connectingView,DisplayObject(Application.application),true); - PopUpManager.centerPopUp(connectingView); - } - - } - - public function closedConnectingView():void{ - if (connectingView!=null){ - connectingView.text="Connection closed success"; - setTimeout(hideConnectingView,3000); - } - } - - public function calleeNotFoundView():void{ - showConnectingView(); - if (connectingView!=null){ - connectingView.text="Callee not found!"; - setTimeout(hideConnectingView,3000); - } - } - public function mediaPortsBusyView():void{ - showConnectingView(); - if (connectingView!=null){ - Logger.info("PhoneView.mediaPortsBusyView()"); - connectingView.text="All media ports is busy"; - setTimeout(hideConnectingView,3000); - } - } - - public function showIncomingView(call:Call):void{ - Logger.info("PhoneView.showIncomingView()"); - DataPhone.getInstance().incommingView.call = call; - PopUpManager.addPopUp(DataPhone.getInstance().incommingView,DisplayObject(Application.application),true); - PopUpManager.centerPopUp(DataPhone.getInstance().incommingView); - } - - public function hideIncomingView():void{ - Logger.info("PhoneView.hideIncomingView()"); - PopUpManager.removePopUp(DataPhone.getInstance().incommingView); - } - - public function showTransferView(call:Call):void{ - Logger.info("PhoneView.showTransferView()"); - DataPhone.getInstance().transferView.call = call; - if (call.state != Call.STATE_HOLD){ - call.setStatusHold(true); - } - PopUpManager.addPopUp(DataPhone.getInstance().transferView,DisplayObject(Application.application),true); - PopUpManager.centerPopUp(DataPhone.getInstance().transferView); - } - - public function hideTransferView():void{ - Logger.info("PhoneView.hideTransferView()"); - PopUpManager.removePopUp(DataPhone.getInstance().transferView); - } - - public function failConnectionView():void{ - if (connectingView!=null){ - Logger.info("PhoneView.failConnectionView()"); - connectingView.text="Connection fail"; - setTimeout(hideConnectingView,3000); - } - } - - public function registerAttemptExpire():void{ - if (connectingView!=null){ - Logger.info("PhoneView.registerAttemptExpire()"); - connectingView.text="Check SIP account settings"; - setTimeout(disconnect,3000); - } - } - - private function disconnect():void{ - DataPhone.getInstance().flash_API.logoff(); - } - - public function pushMessageToInstantMessageChatView(messageObject:Object):void{ - Logger.info("pushMessageToInstantMessageChatView"); - PopUpManager.addPopUp(DataPhone.getInstance().tabChatView,DisplayObject(Application.application)); - PopUpManager.centerPopUp(DataPhone.getInstance().tabChatView); - DataPhone.getInstance().tabChatView.pushMessage(messageObject); - } - - } -} diff --git a/client/client/src/com/flashphoner/phone/views/AccessView.mxml b/client/client/src/com/flashphoner/phone/views/AccessView.mxml deleted file mode 100644 index 7a0479bd..00000000 --- a/client/client/src/com/flashphoner/phone/views/AccessView.mxml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/CallView.mxml b/client/client/src/com/flashphoner/phone/views/CallView.mxml deleted file mode 100644 index 9c2c623d..00000000 --- a/client/client/src/com/flashphoner/phone/views/CallView.mxml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/ConnectingView.mxml b/client/client/src/com/flashphoner/phone/views/ConnectingView.mxml deleted file mode 100644 index aa611d83..00000000 --- a/client/client/src/com/flashphoner/phone/views/ConnectingView.mxml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/DragPanel.as b/client/client/src/com/flashphoner/phone/views/DragPanel.as deleted file mode 100644 index a1dc308e..00000000 --- a/client/client/src/com/flashphoner/phone/views/DragPanel.as +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.phone.views -{ - import flash.events.Event; - import flash.events.MouseEvent; - - import mx.containers.Panel; - import mx.controls.LinkButton; - - public class DragPanel extends Panel{ - - public function DragPanel(){ - super(); - } - - override protected function createChildren():void{ - super.createChildren(); - this.addEventListener(MouseEvent.MOUSE_DOWN,handleDown); - this.addEventListener(MouseEvent.MOUSE_UP,handleUp); - } - override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{ - super.updateDisplayList(unscaledWidth,unscaledHeight); - } - - private function handleDown(e:Event):void{ - this.startDrag(); - } - private function handleUp(e:Event):void{ - this.stopDrag(); - } - - private function closeMe(e:MouseEvent):void{ - this.visible = false; - } - } -} diff --git a/client/client/src/com/flashphoner/phone/views/IncomingView.mxml b/client/client/src/com/flashphoner/phone/views/IncomingView.mxml deleted file mode 100644 index 030ea0e3..00000000 --- a/client/client/src/com/flashphoner/phone/views/IncomingView.mxml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/InfoView.mxml b/client/client/src/com/flashphoner/phone/views/InfoView.mxml deleted file mode 100644 index 80152fda..00000000 --- a/client/client/src/com/flashphoner/phone/views/InfoView.mxml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/InstantMessageChatView.mxml b/client/client/src/com/flashphoner/phone/views/InstantMessageChatView.mxml deleted file mode 100644 index 3317b20e..00000000 --- a/client/client/src/com/flashphoner/phone/views/InstantMessageChatView.mxml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/MainView.mxml b/client/client/src/com/flashphoner/phone/views/MainView.mxml deleted file mode 100644 index a23cb296..00000000 --- a/client/client/src/com/flashphoner/phone/views/MainView.mxml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/MicrophoneSettingsView.mxml b/client/client/src/com/flashphoner/phone/views/MicrophoneSettingsView.mxml deleted file mode 100644 index 8b918d2f..00000000 --- a/client/client/src/com/flashphoner/phone/views/MicrophoneSettingsView.mxml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/PhoneButton.mxml b/client/client/src/com/flashphoner/phone/views/PhoneButton.mxml deleted file mode 100644 index 0608b657..00000000 --- a/client/client/src/com/flashphoner/phone/views/PhoneButton.mxml +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/SipAccountView.mxml b/client/client/src/com/flashphoner/phone/views/SipAccountView.mxml deleted file mode 100644 index a9751f84..00000000 --- a/client/client/src/com/flashphoner/phone/views/SipAccountView.mxml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/TabChatView.mxml b/client/client/src/com/flashphoner/phone/views/TabChatView.mxml deleted file mode 100644 index 46c6f9cd..00000000 --- a/client/client/src/com/flashphoner/phone/views/TabChatView.mxml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - 0){ - numChild --; - tn.removeChildAt(numChild); - } - } - - public function close():void{ - PopUpManager.removePopUp(this); - } - - private function sendInstantMessage():void{ - (InstantMessageChatView(tn.selectedChild)).sendInstantMessage(); - } - - public function pushMessage(messageObject:Object){ - var userNameFrom:String = messageObject["from"].toLowerCase(); - var userNameTo:String = messageObject["to"].toLowerCase(); - var imcv:InstantMessageChatView; - if (tabsMap.containsKey(userNameTo)){ - imcv = tabsMap.getValue(userNameTo); - } else if (tabsMap.containsKey(userNameFrom)){ - imcv = tabsMap.getValue(userNameFrom); - }else{ - imcv = addTab(userNameFrom); - } - imcv.pushMessage(messageObject); - - tn.selectedChild = imcv; - } - ]]> - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/TransferView.mxml b/client/client/src/com/flashphoner/phone/views/TransferView.mxml deleted file mode 100644 index cdd6ed82..00000000 --- a/client/client/src/com/flashphoner/phone/views/TransferView.mxml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/phone/views/VideoView.mxml b/client/client/src/com/flashphoner/phone/views/VideoView.mxml deleted file mode 100644 index 20c09acb..00000000 --- a/client/client/src/com/flashphoner/phone/views/VideoView.mxml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - diff --git a/client/client/src/com/flashphoner/util/HashMap.as b/client/client/src/com/flashphoner/util/HashMap.as deleted file mode 100644 index 96f24d63..00000000 --- a/client/client/src/com/flashphoner/util/HashMap.as +++ /dev/null @@ -1,158 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.util -{ - import flash.utils.Dictionary; - - public class HashMap implements IMap - { - protected var map:Dictionary = null; - - public function HashMap(useWeakReferences:Boolean = true) - { - map = new Dictionary( useWeakReferences ); - } - - public function put(key:*, value:*) : void - { - map[key] = value; - } - - public function putAll(table:Dictionary) : void - { - for ( var prop:* in table ) - { - put( prop, table[prop] ); - } - } - - public function remove(key:*) : void - { - map[ key ] = undefined; - delete map[ key ]; - } - - public function containsKey(key:*) : Boolean - { - return map.hasOwnProperty( key ); - } - - public function containsValue(value:*) : Boolean - { - for ( var key:* in map ) - { - if ( map[ key ] == value ) - { - return true; - } - } - return false; - } - - public function getKey(value:*) : * - { - var identifier:* = undefined; - - for ( var key:* in map ) - { - if ( map[ key ] == value ) - { - identifier = key; - break; - } - } - return identifier; - } - - public function getKeys() : Array - { - var keys:Array = []; - - for ( var key:* in map ) - { - keys.push( key ); - } - return keys; - } - - public function getValue(key:*) : * - { - return map[key]; - } - - public function getValues() : Array - { - var values:Array = []; - - for (var key:* in map) - { - values.push( map[key] ); - } - return values; - } - - public function size() : int - { - var length:int = 0; - - for ( var key:* in map ) - { - length++; - } - return length; - } - - public function isEmpty() : Boolean - { - return size() <= 0; - } - - public function reset() : void - { - for ( var key:* in map ) - { - map[ key ] = undefined; - } - } - - public function resetAllExcept(keyId:*) : void - { - for ( var key:* in map ) - { - if ( key != keyId ) - { - map[ key ] = undefined; - } - } - } - - public function clear() : void - { - for ( var key:* in map ) - { - remove( key ); - } - } - - public function clearAllExcept(keyId:*) : void - { - for ( var key:* in map ) - { - if ( key != keyId ) - { - remove( key ); - } - } - } - } -} diff --git a/client/client/src/com/flashphoner/util/IMap.as b/client/client/src/com/flashphoner/util/IMap.as deleted file mode 100644 index dd9b6b27..00000000 --- a/client/client/src/com/flashphoner/util/IMap.as +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -package com.flashphoner.util -{ - import flash.utils.Dictionary; - - public interface IMap - { - function put(key:*, value:*) : void; - - function putAll(table:Dictionary) : void; - - function remove(key:*) : void; - - function containsKey(key:*) : Boolean; - - function containsValue(value:*) : Boolean; - - function getKey(value:*) : *; - - function getValue(key:*) : *; - - function getKeys() : Array; - - function getValues() : Array; - - function size() : int; - - function isEmpty() : Boolean; - - function reset() : void; - - function resetAllExcept(key:*) : void; - - function clear() : void; - - function clearAllExcept(key:*) : void; - } -} diff --git a/client/client/src/flashphoner.xml b/client/client/src/flashphoner.xml deleted file mode 100644 index 5aa46aae..00000000 --- a/client/client/src/flashphoner.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - 87.226.225.59 - 8080 - 8443 - false - 1935 - true - true - - phone_app - 176 - 144 - true - true - - - - - diff --git a/client/client/src/flashphoner_js_api.mxml b/client/client/src/flashphoner_js_api.mxml deleted file mode 100644 index d77252b3..00000000 --- a/client/client/src/flashphoner_js_api.mxml +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - - - - diff --git a/client/client/src/js/Click2Call.js b/client/client/src/js/Click2Call.js deleted file mode 100644 index d5047103..00000000 --- a/client/client/src/js/Click2Call.js +++ /dev/null @@ -1,718 +0,0 @@ -/* - Copyright (c) 2011 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. - Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ -var flashphoner; -var flashphoner_UI; -var flashphonerLoader; -var flashphonerListener; - -// One call become two calls during TRANSFER case -// there is why we need at least two kinds of calls here -var currentCall = null; -var callee = ''; -var callerLogin = ''; -var registerRequired; -var isLogged = false; - -var micVolume = 100; -var speakerVolume = 100; -var traceEnabled = true; -var intervalId = -1; -var proportion = 0; -var proportionStreamer = 0; -var callToken = "testcalltoken"; - -var timerHours = 0; -var timerMinutes = 0; -var timerSeconds = 0; -var timerTimeout; - -var testInviteParameter = new Object; -testInviteParameter['param1'] = "value1"; -testInviteParameter['param2'] = "value2"; - -var logs=""; - -function timer() { - - if (timerHours < 10) { - mTimerHours = "0" + timerHours - } else { - mTimerHours = timerHours - } - if (timerMinutes < 10) { - mTimerMinutes = "0" + timerMinutes - } else { - mTimerMinutes = timerMinutes - } - if (timerSeconds < 10) { - mTimerSeconds = "0" + timerSeconds - } else { - mTimerSeconds = timerSeconds - } - - $("#timer").html(mTimerHours + ":" + mTimerMinutes + ":" + mTimerSeconds); - - timerSeconds = timerSeconds + 1; - - if (timerSeconds == 60) { - timerMinutes = timerMinutes + 1; - timerSeconds = 0; - } - - if (timerMinutes == 60) { - timerHours = timerHours + 1; - timerMinutes = 0; - } - - timerTimeout = setTimeout("timer()", 1000); -} - -$(document).ready(function () { - changeCallStateInfo("...Loading..."); - flashphonerLoader = new FlashphonerLoader(); -}); - - -function loginByToken(token) { - trace("Click2Call - loginByToken url: "+ document.URL+" token: "+ token); - changeCallStateInfo("...Registering..."); - - var pageUrl = document.URL; - var result = flashphoner.loginByToken(flashphonerLoader.urlServer, token, pageUrl); -} - -function getInfoAboutMe() { - trace("Click2Call - getInfoAboutMe"); - return flashphoner.getInfoAboutMe(); -} - -function logoff() { - trace("Click2Call - logoff"); - flashphoner.logoff(); -} - -function callByToken(token) { - trace("Click2Call - callByToken "+ token); - if (isLogged) { - if (!hasAccessToAudio()) { - intervalId = setInterval('if (hasAccessToAudio()){flashphoner_UI.closeRequestUnmuteC2C(); clearInterval(intervalId);callByToken(callToken);}', 500); - flashphoner_UI.requestUnmuteC2C(); - } else if (hasAccessToAudio()) { - var callRequest = {}; - callRequest.token = token; - callRequest.inviteParameters = testInviteParameter; - callRequest.isMsrp = false; - callRequest.hasVideo = false; - var result = flashphoner.callByToken(callRequest); - if (result == 0) { - changeCallStateInfo("...Calling..."); - toHangupState(); - flashphonerListener.onCall(); - } - } else { - openInfoView("Microphone is not plugged in", 3000); - } - } else { - if (flashphonerLoader.getToken()) { - loginByToken(flashphonerLoader.getToken()); - } else { - console.log("Please, specify token in flashphoner.xml!"); - } - } -} - -function hangup(callId) { - trace("Click2Call - hangup "+ callId); - flashphoner.hangup(callId); - flashphonerListener.onHangup(); -} - -function sendDTMF(callId, dtmf) { - trace("Click2Call - sendDTMF callId: "+ callId+" dtmf: "+ dtmf); - flashphoner.sendDTMF(callId, dtmf); -} - -// TODO change img to background -function sendVideoChangeState() { - trace("Click2Call - sendVideoChangeState"); - var sendVideoButton = $('.sendVideoButton'); - var sendVideoButtonImage = $('#sendVideoButtonImage'); - - if (sendVideoButton.hasClass('on')) { - sendVideoButton.toggleClass('on'); - sendVideoButtonImage.attr('src', 'assets/c2c_play.png') - flashphoner.setSendVideo(false); - } else { - sendVideoButton.toggleClass('on'); - sendVideoButtonImage.attr('src', 'assets/c2c_pause.png') - flashphoner.setSendVideo(true); - } -} - -function initSendVideoButton() { - var sendVideoButton = $('.sendVideoButton'); - var sendVideoButtonImage = $('#sendVideoButtonImage'); - if (sendVideoButton.hasClass('on')) { - sendVideoButton.toggleClass('on'); - sendVideoButtonImage.attr('src', 'assets/c2c_play.png'); - flashphoner.setSendVideo(false); - } -} - -function changeRelationMyVideo(relation) { - trace("Click2Call - changeRelationMyVideo "+ relation); - flashphoner.changeRelationMyVideo(relation); -} - -function getMicVolume() { - var ret = flashphoner.getMicVolume(); - trace("Click2Call - getMicVolume "+ret); - return ret; -} -function getVolume() { - var ret = flashphoner.getVolume(); - trace("Click2Call - getVolume "+ret); - return ret; -} - -function getVersion() { - var ret = flashphoner.getVersion(); - trace("Click2Call - getVersion "+ret); - return ret; -} - -function hasAccessToAudioAndVideo() { - return hasAccessToAudio() && hasAccessToVideo(); -} - -function hasAccessToAudio() { - return flashphoner.hasAccessToAudio(); -} - -function hasAccessToVideo() { - return flashphoner.hasAccessToVideo(); -} -/* ------------------ Notify functions ----------------- */ - -function addLogMessage(message) { - trace('Click2Call - addLogMessage '+ message); -} - -function notifyConfigLoaded() { - trace("Click2Call - notifyConfigLoaded"); - flashphoner = flashphonerLoader.getFlashphoner(); - flashphoner_UI = flashphonerLoader.getFlashphonerUI(); - flashphonerListener = flashphonerLoader.getFlashphonerListener(); - if (flashphonerLoader.useWebRTC) { - $('#cameraButton').css('visibility', 'hidden'); - $('#micButton').css('visibility', 'hidden'); - } else { - $("#micSlider").slider("option", "value", getMicVolume()); - } - - if (flashphonerLoader.getToken()) { - loginByToken(flashphonerLoader.getToken()); - } else { - console.log("Please, specify token in flashphoner.xml!"); - } - $("#speakerSlider").slider("option", "value", getVolume()); -} - -function notifyRegisterRequired(registerR) { - registerRequired = registerR; -} - -function notifyCloseConnection() { - trace("Click2Call - notifyCloseConnection"); - currentCall = null; - toCallState(); - isLogged = false; - closeVideoView(); - initSendVideoButton(); - changeCallStateInfo("Finished"); -} - -function notifyConnected() { - trace("Click2Call - notifyConnected"); - if (!registerRequired) { - isLogged = true; - callByToken(callToken); - } -} - -function notifyRegistered() { - trace("Click2Call - notifyRegistered"); - if (registerRequired) { - changeCallStateInfo("Registered"); - isLogged = true; - flashphonerListener.onRegistered(); - callByToken(callToken); - } -} - -function notifyBalance(balance) { -} - -// This functions invoked every time when call state changed -function notify(call) { - trace('Click2Call - notify call_id: '+ call.id +' call.anotherSideUser: '+ call.anotherSideUser); - if (call.incoming) { - //do nothing because we already hangup this call in notifyAddCall() - return; - } - if (currentCall.id == call.id) { - currentCall = call; - if (currentCall.visibleNameCallee != null) { - if (currentCall.visibleNameCallee.length > 11) { - $('#caller').css('font-size', 20); - $('#caller').css('top', 95); - } - $('#caller').html(currentCall.visibleNameCallee.replace(/^<|>$/g, "")); - } else { - $('#caller').html(currentCall.callee); - } - // if we finish the call - if (call.state == STATE_FINISH) { - proportion = 0; - closeVideoView(); - initSendVideoButton(); - changeCallStateInfo("Finished"); - toCallState(); - flashphoner.stopSound("RING"); - flashphoner.playSound("FINISH"); - - timerMinutes = 0; - timerHours = 0; - timerSeconds = 0; - $("#timer").hide(); - clearTimeout(timerTimeout); - // if call is holded - } else if (call.state == STATE_HOLD) { - changeCallStateInfo("...Holded..."); - // or if call is started talk - } else if (call.state == STATE_TALK) { - changeCallStateInfo("...Talking..."); - flashphoner.stopSound("RING"); - timer(); - $("#timer").show(); - // or if we just ringing - } else if (call.state == STATE_RING) { - changeCallStateInfo("...Ringing..."); - flashphoner.playSound("RING"); - } else if (call.state == STATE_BUSY) { - flashphoner.playSound("BUSY"); - changeCallStateInfo("Busy"); - } - } -} - -function notifyCallbackHold(call, isHold) { -} - -function notifyCost(cost) { -} - -function notifyBugReport(filename) { - trace("Created bug report; filename - " + filename); -} - -function notifyError(error) { - - trace("Click2Call - notifyError "+ error); - - if (error == CONNECTION_ERROR || error == TOO_MANY_REGISTER_ATTEMPTS || - error == LICENSE_RESTRICTION || error == LICENSE_NOT_FOUND || - error == REGISTER_EXPIRE || error == MEDIA_PORTS_BUSY) { - openInfoView("Connection error, try later", 3000); - } else if (error == AUTHENTICATION_FAIL || error == SIP_PORTS_BUSY || - error == WRONG_SIPPROVIDER_ADDRESS) { - openInfoView("Connection error, try later", 3000); - window.setTimeout("logoff();", 3000); - } else if (error == USER_NOT_AVAILABLE) { - openInfoView("Support is offline", 3000); - } else if (error == INTERNAL_SIP_ERROR) { - openInfoView("Unknown error", 3000); - } - toCallState(); - flashphonerListener.onError(); -} - -function notifyVideoFormat(call) { - trace("Click2Call - notifyVideoFormat "+ call.id); - - // proportionStreamer allow us change proportion of small video window (myself preview video) - if (call.streamerVideoWidth != 0) { - proportionStreamer = call.streamerVideoHeight / call.streamerVideoWidth; - if (proportionStreamer != 0) { - /** Here we change size of small myself preview video window in the swf from the js code. - * To be precise we cnahge only height, width is fixed and equal to 20% of big video. - */ - changeRelationMyVideo(proportionStreamer); - } - } - - if (!call.playerVideoHeight == 0) { //that mean other side really send us video - proportion = call.playerVideoHeight / call.playerVideoWidth; //set proportion of video picture, else it will be = 0 - var newHeight = 320 * proportion; - $('.video').height(newHeight); - $('#video').height(newHeight).width(320); - //$('#c2c').height(newHeight+40); - } -} - -function notifyOpenVideoView(isViewed) { - trace("Click2Call - notifyOpenVideoView: isViewed: " + isViewed); - if (isViewed) { - openVideoView('big'); - } else { - closeVideoView(); - } -} - -function notifyMessage(messageObject) { - trace('Click2Call - notifyMessage from: '+ messageObject.from+' body: '+ messageObject.body); -} - -function notifyAddCall(call) { - trace("Click2Call - notifyAddCall call.id: "+ call.id +" call.anotherSideUser: "+ call.anotherSideUser); - if (call.incoming == true) { - hangup(call.id); - } else { - currentCall = call; - $('#caller').html(currentCall.anotherSideUser); - } -} - -function notifyRemoveCall(call) { - trace("Click2Call - notifyRemoveCall "+ call.id); - if (currentCall != null && currentCall.id == call.id) { - currentCall = null; - flashphonerListener.onRemoveCall(); - } -} - -function notifyVersion(version) { - getElement('versionOfProduct').innerHTML = version; -} -/* ----------------------------------------------------------------------- */ - -function openInfoView(str, timeout) { - if (timeout != 0) { - window.setTimeout("closeInfoView();", timeout); - } - getElement('infoDiv').style.visibility = "visible"; - getElement('infoDiv').innerHTML = str; -} - -function changeCallStateInfo(str) { - $('#callState').html(str); -} - -function closeInfoView(timeout) { - trace("Click2Call - closeInfoView "+timeout); - if (timeout != 0) { - window.setTimeout("getElement('infoDiv').style.visibility = 'hidden';", timeout); - } else { - getElement('infoDiv').style.visibility = "hidden"; - } -} - -function openSettingsView() { - trace("Click2Call - openSettingsView"); - getElement('settingsDiv').style.visibility = "visible"; -} -function closeSettingsView() { - trace("Click2Call - closeSettingsView"); - getElement('settingsDiv').style.visibility = "hidden"; -} - -function getElement(str) { - return document.getElementById(str); -} - -function toHangupState() { - trace("Click2Call - toHangupState"); - $('#callButton').html('Hangup').addClass('hangup').removeClass('call'); - disableCallButton(); -} - -function toCallState() { - trace("Click2Call - toCallState"); - $('#callButton').html('Call').addClass('call').removeClass('hangup'); - disableCallButton(); -} - -function disableCallButton() { - trace("Click2Call - disableCallButton"); - var button = $('#callButton'); - - $('#callButton').addClass('disabled'); - window.setTimeout(enableCallButton, 3000); - - function enableCallButton() { - $('#callButton').removeClass('disabled'); - } -} - -/* ----- VIDEO ----- */ - -function openVideoView(size) { - trace("Click2Call - openVideoView "+ size); - flashphoner_UI.openVideoView(); - $('#cameraButton').addClass('pressed'); - // if we already give access to devices when trying to open video view - if (hasAccessToVideo()) { - - // show send my video button - $('.sendVideoButton').show(); - - // if we need show only myself video (when other side dont send us video) - // or if we need show both videos - ourselves and partner`s - if ((size == 'big') && (proportion != 0)) { // sometimes voip servers send video with null sizes. Here we defend from such cases - $('#flash').removeClass('init').addClass('video'); - var newHeight = 320 * proportion; - $('.video').height(newHeight); - $('#video').height(newHeight).width(320); - $('#c2c').height(newHeight + 40); - } else if (size == 'small') { - $('#flash').removeClass('init').addClass('video'); - $('#video').height(240).width(320); - } else { - $('#flash').removeClass('init').addClass('video'); - $('#video').height(240).width(320); - - } - - // or if we did not access the devices yet - } else { - flashphoner_UI.requestUnmuteC2C(); - intervalId = setInterval('if (hasAccessToVideo()){flashphoner_UI.closeRequestUnmuteC2C(); clearInterval(intervalId); openVideoView("small");}', 500); - } -} - -function closeVideoView() { - trace("Click2Call - closeVideoView"); - // turn flash div back to init size - $('#flash').removeClass().removeAttr('style').addClass('init'); - // turn c2c div back to init size - $('#c2c').height(240); - // hide send video button - $('.sendVideoButton').hide(); - // unpressed camerabutton - $('#cameraButton').removeClass('pressed'); -} - -// functions closeView is simplifying of many close....View functions -function close(element) { - element.css('visibility', 'hidden'); -} - -/* TODO make good auto trace - function getFnName(fn) { - return fn.toString().match(/function ([^(]*)\(/)[1]; - } - */ - - -/* --------------------- On document load we do... ------------------ */ -$(function () { - - // load c2c interface in frame c2c-test for showing in popup - // $('#c2c-test').load('Click2callJS.html', alert('done')); - - // All buttons except .call and .hangup stay in press state until double click - $(".button:not(.dialButton, .call, .hangup, .disabled)").click(function () { - $(this).toggleClass('pressed'); - }); - - // All dial buttons and call/hangup go unpressed after mouseup. Except if it disabled mode. - $('.dialButton, .call, .hangup').mousedown(function () { - if (!$(this).hasClass('disabled')) { - $(this).addClass('pressed'); - } - }).mouseup(function () { - $(this).removeClass('pressed'); - }).mouseover(function () { - $(this).removeClass('pressed'); - }); - - // dialpad button opens dialpad - $("#dialpadButton").click(function () { - if ($(this).hasClass('pressed')) { - $('#dialPad').show(); - } else { - $('#dialPad').hide(); - } - }); - - // dialButtons sends DTMF signals - $(".dialButton").click(function () { - if (currentCall != null && currentCall.state == STATE_TALK) { - sendDTMF(currentCall.id, $(this).html()); - var dialScreenText = $('.dialScreen').html(); - if (dialScreenText.length > 10) { - $('.dialScreen').html(dialScreenText.substr(1) + $(this).html()); - } else { - $('.dialScreen').append($(this).html()); - } - } - }); - - // mic button opens mic slider - $("#micButton").click(function () { - if ($(this).hasClass('pressed')) { - $('#micSlider').show(); - $('#micBack').show(); - } else { - $('#micSlider').hide(); - $('#micBack').hide(); - } - }); - - // sound button opens sound slider - $("#soundButton").click(function () { - if ($(this).hasClass('pressed')) { - $('#speakerSlider').show(); - $('#speakerBack').show(); - } else { - $('#speakerSlider').hide(); - $('#speakerBack').hide(); - } - }); - - // call button makes call or hangup - $("#callButton:not(.disabled)").click(function () { - if (!$(this).hasClass('disabled')) { - if ($(this).html() == 'Call') { - callByToken(callToken); - } else { - hangup(currentCall.id); - } - } - }); - - - // call me button opens new window with click2call - $("#callMeButton1:not(.disabled)").click(function () { - window.open('click2call-test-1.html', '_blank', 'width=340,height=260,resizable=no,toolbar=no,menubar=no,location=no,status=no,scrollbar=no') - }); - - $("#callMeButton2:not(.disabled)").click(function () { - window.open('click2call-test-2.html', '_blank', 'width=340,height=260,resizable=no,toolbar=no,menubar=no,location=no,status=no,scrollbar=no') - }); - - $("#callMeButton3:not(.disabled)").click(function () { - window.open('click2call-test-3.html', '_blank', 'width=340,height=260,resizable=no,toolbar=no,menubar=no,location=no,status=no,scrollbar=no') - }); - - // Mic slider set mic volume when you slide it - $("#micSlider").slider({ - orientation: "vertical", - range: "min", - min: 0, - max: 100, - value: 60, - slide: function (event, ui) { - flashphoner.setMicVolume(ui.value); - } - }); - - // Speaker slider set speaker volume when you slide it - $("#speakerSlider").slider({ - orientation: "vertical", - range: "min", - min: 0, - max: 100, - value: 60, - slide: function (event, ui) { - flashphoner.setVolume(ui.value); - } - }); - - // Camera button opens video window. - // Depends on situation it can be both video or just my video - $("#cameraButton").click(function () { - if ($(this).hasClass('pressed')) { - $('.sendVideoButton').show(); - if (proportion != 0) { - openVideoView('big'); - } else { - openVideoView('small'); - } - } else { - $('.sendVideoButton').hide(); - closeVideoView(); - } - }); - - // bind effects to click on send video button - // and toggle video on/off by clicking - $('.sendVideoButton').mousedown(function () { - $(this).addClass('sendVideoButtonPressed'); - }).mouseup(function () { - $(this).removeClass('sendVideoButtonPressed'); - }).mouseover(function () { - $(this).removeClass('sendVideoButtonPressed'); - }).click(function () { - sendVideoChangeState(); - }); - - // Settings button button opens settings view - $("#settingsButton").click(function () { - if ($(this).hasClass('pressed')) { - - $("#settingsView").show(); - - var micList = flashphoner.getMicropones(); - var camList = flashphoner.getCameras(); - - //clear it each time, else we append it more and more... - $("#micSelector").html(""); - $("#camSelector").html(""); - - for (var i = 0; i < micList.length; i++) { - $("#micSelector").append(''); - } - - // we use here index instead of name because AS getcamera can only use indexes - for (var i = 0; i < camList.length; i++) { - $("#camSelector").append(''); - } - - } else { - $("#settingsView").hide(); - } - }); - - - $("#micSelector").change(function () { - flashphoner.setMicrophone($(this).val()); - trace('Click2Call - Microphone was changed to '+ $(this).val()); - }); - - $("#camSelector").change(function () { - flashphoner.setCamera($(this).val()); - trace('Click2Call - Camera was changed to '+ $(this).val()); - }); - - $("#settingsOkButton").click(function () { - $("#settingsView").hide(); - $("#settingsButton").removeClass("pressed"); - }); - -}); - - - - \ No newline at end of file diff --git a/client/client/src/js/FlashphonerLoader.js b/client/client/src/js/FlashphonerLoader.js deleted file mode 100644 index 8e09ffa6..00000000 --- a/client/client/src/js/FlashphonerLoader.js +++ /dev/null @@ -1,370 +0,0 @@ -/* - Copyright (c) 2011 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ -FlashphonerLoader = function (config) { - this.flashphoner = null; - this.flashphoner_UI = null; - this.flashphonerListener = new DefaultListener(); - this.useWebRTC = false; - this.urlServer = null; - this.wcsIP = null; - this.wsPort = "8080"; - this.flashPort = "1935"; - this.appName = "phone_app"; - this.loadBalancerUrl = null; - this.jsonpSuccess = false; - this.token = null; - this.registerRequired = true; - this.useDTLS = true; - this.videoWidth = 320; - this.videoHeight = 240; - this.pushLogEnabled = false; - this.ringSound = "sounds/CALL_OUT.ogg"; - this.busySound = "sounds/BUSY.ogg"; - this.registerSound = "sounds/REGISTER.ogg"; - this.finishSound = "sounds/HANGUP.ogg"; - this.xcapUrl = null; - this.msrpCallee = null; - this.subscribeEvent = null; - this.contactParams = null; - this.imdnEnabled = false; - this.msgContentType = "text/plain"; - this.stripCodecs = new Array(); - this.stunServer = ""; - this.disableLocalRing = false; - this.modeLT = false; - this.hangupLT = 0; - this.answerLT = 0; - this.callLT = 0; - - $.ajax({ - type: "GET", - url: "flashphoner.xml", - dataType: "xml", - success: this.parseFlashphonerXml, - context: this - }); -}; - -FlashphonerLoader.prototype = { - - parseFlashphonerXml: function (xml) { - var me = this; - var wcsIP = $(xml).find("wcs_server"); - if (wcsIP.length > 0) { - this.wcsIP = wcsIP[0].textContent; - } else { - openConnectingView("Can not find 'wcs_server' in flashphoner.xml", 0); - return; - } - var wsPort = $(xml).find("ws_port"); - if (wsPort.length > 0) { - this.wsPort = wsPort[0].textContent; - } - var wssPort = $(xml).find("wss_port"); - if (wssPort.length > 0) { - this.wssPort = wssPort[0].textContent; - } - var useWss= $(xml).find("use_wss"); - if (useWss.length > 0) { - this.useWss = "true" == useWss[0].textContent; - } - - var flashPort = $(xml).find("flash_port"); - if (flashPort.length > 0) { - this.flashPort = flashPort[0].textContent; - } - var appName = $(xml).find("application"); - if (appName.length > 0) { - this.appName = appName[0].textContent; - } - var loadBalancerUrl = $(xml).find("load_balancer_url"); - if (loadBalancerUrl.length > 0) { - this.loadBalancerUrl = loadBalancerUrl[0].textContent; - } - var token = $(xml).find("token"); - if (token.length > 0) { - this.token = token[0].textContent; - } - var registerRequired = $(xml).find("register_required"); - if (registerRequired.length > 0) { - this.registerRequired = (registerRequired[0].textContent === "true"); - } - - var useDTLS = $(xml).find("use_dtls"); - if (useDTLS.length > 0) { - this.useDTLS = (useDTLS[0].textContent === "true"); - } - - var videoWidth = $(xml).find("video_width"); - if (videoWidth.length > 0) { - this.videoWidth = videoWidth[0].textContent; - } - var videoHeight = $(xml).find("video_height"); - if (videoHeight.length > 0) { - this.videoHeight = videoHeight[0].textContent; - } - - var pushLogEnabled = $(xml).find("push_log"); - if (pushLogEnabled.length) { - this.pushLogEnabled = pushLogEnabled.text(); - } - - //Sounds for WebRTC implementation - var ringSound = $(xml).find("ring_sound"); - if (ringSound.length > 0) { - if (ringSound[0].textContent.length) { - this.ringSound = ringSound[0].textContent; - } - } - var busySound = $(xml).find("busy_sound"); - if (busySound.length > 0) { - if (busySound[0].textContent.length) { - this.busySound = busySound[0].textContent; - } - } - var registerSound = $(xml).find("register_sound"); - if (registerSound.length > 0) { - if (registerSound[0].textContent.length) { - this.registerSound = registerSound[0].textContent; - } - } - var finishSound = $(xml).find("finish_sound"); - if (finishSound.length > 0) { - if (finishSound[0].textContent.length) { - this.finishSound = finishSound[0].textContent; - } - } - - var xcapUrl = $(xml).find("xcap_url"); - if (xcapUrl.length > 0) { - if (xcapUrl[0].textContent.length) { - this.xcapUrl = xcapUrl[0].textContent; - } - } - - var msrpCallee = $(xml).find("msrp_callee"); - if (msrpCallee.length > 0) { - if (msrpCallee[0].textContent.length) { - this.msrpCallee = msrpCallee[0].textContent; - } - } - - var subscribeEvent = $(xml).find("subscribe_event"); - if (subscribeEvent.length > 0) { - if (subscribeEvent[0].textContent.length) { - this.subscribeEvent = subscribeEvent[0].textContent; - } - } - - var contactParams = $(xml).find("contact_params"); - if (contactParams.length > 0) { - if (contactParams[0].textContent.length) { - this.contactParams = contactParams[0].textContent; - } - } - - var imdnEnabled = $(xml).find("imdn_enabled"); - if (imdnEnabled.length > 0) { - if (imdnEnabled[0].textContent.length) { - this.imdnEnabled = Boolean(imdnEnabled[0].textContent); - } - } - - var disableLocalRing = $(xml).find("disable_local_ring"); - if (disableLocalRing.length > 0) { - if (disableLocalRing[0].textContent.length) { - this.disableLocalRing = Boolean(disableLocalRing[0].textContent); - } - } - console.log("disableLocalRing: "+this.disableLocalRing); - - //Message content type by default "text/plain", can be "message/cpim" - var msgContentType = $(xml).find("msg_content_type"); - if (msgContentType.length > 0) { - this.msgContentType = msgContentType.text(); - console.log("Message content type: " + this.msgContentType); - } - - var stripCodecs = $(xml).find("strip_codecs"); - if (stripCodecs.length > 0) { - var tempCodecs = stripCodecs[0].textContent.split(","); - for (i = 0; i < tempCodecs.length; i++) { - if (tempCodecs[i].length) this.stripCodecs[i] = tempCodecs[i]; - console.log("Codec " + tempCodecs[i] + " will be removed from SDP!"); - } - } - - //stun server address - var stunServer = $(xml).find("stun_server"); - if (stunServer.length > 0) { - this.stunServer = stunServer.text(); - console.log("Stun server: " + this.stunServer); - } - - //variable participating in api load, can bee null, webrtc, flash - var streamingType = $(xml).find("streaming"); - if (streamingType.length > 0) { - if (streamingType.text() == "webrtc") { - console.log("Force WebRTC usage!"); - isWebRTCAvailable = true; - } else if (streamingType.text() == "flash") { - console.log("Force Flash usage!"); - isWebRTCAvailable = false; - } else { - console.log("Bad streaming property " + streamingType.text() + - ", can be webrtc or flash. Using default behaviour!") - } - } - - //Load Tool mode on/off - var modeLT = $(xml).find("modeLT"); - if (modeLT.length > 0) { - if (modeLT[0].textContent.length) { - this.modeLT = Boolean(modeLT[0].textContent); - } - } - - //call duration in seconds when Load Tool is enabled, callee will hangup after this timeout. - // Hangup will not occur in case of 0 timeout. - var hangupLT = $(xml).find("hangupLT"); - if (hangupLT.length > 0) { - this.hangupLT = hangupLT[0].textContent; - } - - //Answer timeout when Load Tool is enabled, if greater than 0 callee answer the call after specified amount of seconds - var answerLT = $(xml).find("answerLT"); - if (answerLT.length > 0) { - this.answerLT = answerLT[0].textContent; - } - - //Recall timeout when Load Tool is enabled, specifies how long caller must wait after hangup to place another call. - var callLT = $(xml).find("callLT"); - if (callLT.length > 0) { - this.callLT = callLT[0].textContent; - } - - //get load balancer url if load balancing enabled - if (me.loadBalancerUrl != null) { - trace("FlashphonerLoader - Retrieve server url from load balancer"); - - /* - * this timeout is a workaround to catch errors from ajax request - * Unfortunately jQuery do not support error callback in case of JSONP - */ - setTimeout(function () { - //check status of ajax request - if (!me.jsonpSuccess) { - trace("FlashphonerLoader - Error occurred while retrieving load balancer data, please check your load balancer url " + - me.loadBalancerUrl); - me.loadAPI(); - } - }, 10000) - var loadBalancerData = null; - $.ajax({ - type: "GET", - url: me.loadBalancerUrl, - dataType: "jsonp", - data: loadBalancerData, - success: function (loadBalancerData) { - me.wcsIP = loadBalancerData.server; - me.wsPort = loadBalancerData.ws; - me.wssPort = loadBalancerData.wss; - me.flashPort = loadBalancerData.flash; - me.jsonpSuccess = true; - trace("FlashphonerLoader - Connection data from load balancer: " - + "wcsIP " + loadBalancerData.server - + ", wsPort " + loadBalancerData.ws - + ", wssPort " + loadBalancerData.wss - + ", flashPort " + loadBalancerData.flash); - me.loadAPI(); - } - }); - } else { - me.loadAPI(); - } - }, - - loadAPI: function () { - var me = this; - if (isWebRTCAvailable) { - me.useWebRTC = true; - var protocol = "ws://"; - var port = this.wsPort; - if (this.useWss){ - protocol = "wss://"; - port = this.wssPort; - } - me.urlServer = protocol + this.wcsIP + ":" + port; - me.flashphoner = new WebSocketManager(getElement('localVideoPreview'), getElement('remoteVideo')); - if (me.stripCodecs.length) me.flashphoner.setStripCodecs(me.stripCodecs); - if (me.stunServer != "") me.flashphoner.setStunServer(me.stunServer); - me.flashphoner_UI = new UIManagerWebRtc(); - if (me.modeLT) me.flashphonerListener = new LoadToolListener(); - notifyConfigLoaded(); - } else { - me.useWebRTC = false; - me.urlServer = "rtmfp://" + this.wcsIP + ":" + this.flashPort + "/" + this.appName; - var params = {}; - params.menu = "true"; - params.swliveconnect = "true"; - params.allowfullscreen = "true"; - params.allowscriptaccess = "always"; - //in case of Safari wmode should be "window" - if((navigator.userAgent.indexOf("Safari") > -1) && !(navigator.userAgent.indexOf("Chrome") > -1)) { - params.wmode = "window"; - //workaround for safari browser, FPNR-403 - swfobject.switchOffAutoHideShow(); - } else { - params.wmode = "transparent"; - } - var attributes = {}; - var flashvars = {}; - flashvars.config = "flashphoner.xml"; - - if (this.hasFlash()) { - swfobject.embedSWF("flashphoner_js_api.swf", "videoDiv", "100%", "100%", "11.2.202", "expressInstall.swf", flashvars, params, attributes, function (e) { - me.flashphoner = e.ref; - me.flashphoner_UI = new UIManagerFlash(); - if (me.modeLT) me.flashphonerListener = new LoadToolListener(); - }); - } else { - notifyFlashNotFound(); - } - - } - - }, - - hasFlash: function () { - return swfobject.hasFlashPlayerVersion("11.2"); - }, - - getFlashphoner: function () { - return this.flashphoner; - }, - - getFlashphonerUI: function () { - return this.flashphoner_UI; - }, - - getFlashphonerListener: function () { - return this.flashphonerListener; - }, - - getToken: function () { - return this.token; - } -}; - - - diff --git a/client/client/src/js/Phone.js b/client/client/src/js/Phone.js deleted file mode 100644 index 32371d45..00000000 --- a/client/client/src/js/Phone.js +++ /dev/null @@ -1,1315 +0,0 @@ -/* - Copyright (c) 2011 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ - -var flashphoner; -var flashphoner_UI; -var flashphonerLoader; -var flashphonerListener; - -// One call become two calls during TRANSFER case -// there is why we need at least two kinds of calls here -var holdedCall = null; -var currentCall = null; -// not sure if "callee" is reserved word so I will use callee /Pavel -var callee = ''; -var callerLogin = ''; -var registerRequired; -var isLogged = false; - -var needOpenTransferView = false; -var connectingViewBeClosed = false; -var traceEnabled = true; -var intervalId = -1; -var proportion = 0; - -var testInviteParameter = {}; -testInviteParameter['param1'] = "value1"; -testInviteParameter['param2'] = "value2"; - -var messenger; - -var logs=""; - -$(document).ready(function () { - toLogOffState(); - openConnectingView("Loading...", 0); - flashphonerLoader = new FlashphonerLoader(); -}); - - -function login() { - trace("Phone - login"); - connectingViewBeClosed = false; - - if ($("#outbound_proxy").val() == "") { - $("#outbound_proxy").val($("#domain").val()); - } - - var loginObject = {}; - loginObject.login = $('#username').val(); - loginObject.password = $('#password').val(); - loginObject.authenticationName = $('#authname').val(); - loginObject.domain = $('#domain').val(); - loginObject.outboundProxy = $('#outbound_proxy').val(); - loginObject.port = $('#port').val(); - loginObject.useProxy = $('#checkboxUseProxy').attr("checked") ? true : false; - loginObject.registerRequired = flashphonerLoader.registerRequired; - loginObject.useDTLS = flashphonerLoader.useDTLS; - if (flashphonerLoader.contactParams != null && flashphonerLoader.contactParams.length != 0) { - loginObject.contactParams = flashphonerLoader.contactParams; - } - - trace("Phone - loginObject login: "+loginObject.login+" authenticationName: "+loginObject.authenticationName+" registerRequired: "+registerRequired+" useDTLS: "+loginObject.useDTLS); - - var result = flashphoner.login(loginObject, flashphonerLoader.urlServer); - closeLoginView(); - if (result == 0) { - openConnectingView("Connecting...", 0); - setCookie("login", $('#username').val()); - setCookie("authName", $('#authname').val()); - setCookie("pwd", $('#password').val()); - setCookie("domain", $('#domain').val()); - setCookie("outbound_proxy", $('#outbound_proxy').val()); - setCookie("port", $('#port').val()); - } -} - -function loginByToken(token) { - trace("Phone - loginByToken "+ token); - connectingViewBeClosed = false; - var result = flashphoner.loginByToken(flashphonerLoader.urlServer, token, document.URL); - - closeLoginView(); - openConnectingView("Connecting...", 0); -} - -function getInfoAboutMe() { - trace("Phone - getInfoAboutMe"); - return flashphoner.getInfoAboutMe(); -} - -function logoff() { - trace("Phone - logoff"); - flashphoner.logoff(); -} - -function msrpCall(callee) { - trace("Phone - msrpCall "+callee); - flashphoner.msrpCall({callee: callee, visibleName: 'Caller', hasVideo: false, inviteParameters: testInviteParameter, isMsrp: true}); -} - -function call() { - trace("Phone - call "+callee); - if (isLogged) { - var hasAccess; - if (isVideoCall()){ - hasAccess = hasAccessToAudioAndVideo; - } else { - hasAccess = hasAccessToAudio; - } - if (!hasAccess()) { - if (intervalId == -1) { - intervalId = setInterval('if (isVideoCall() ? hasAccessToAudioAndVideo() : hasAccessToAudio()){flashphoner_UI.closeRequestUnmute(); clearInterval(intervalId); intervalId = -1; call();}', 500); - } - if (isVideoCall()){ - flashphoner_UI.getAccessToAudioAndVideo(); - } else { - flashphoner_UI.getAccessToAudio(); - } - } else if (hasAccess()) { - var result = flashphoner.call({callee: callee, visibleName: 'Caller', hasVideo: isVideoCall(), inviteParameters: testInviteParameter, isMsrp: false}); - if (result == 0) { - toHangupState(); - flashphonerListener.onCall(); - } else { - openConnectingView("Callee number is wrong", 3000); - } - } else { - openConnectingView("Microphone is not plugged in", 3000); - } - } else { - openLoginView(); - } -} - -function notifyMessage(message, notificationResult, sipObject) { - messenger.notifyMessage(message, notificationResult, sipObject); -} - -function sendMessage(to, body, contentType) { - trace("Phone - sendMessage "+ to+" body: "+ body+" contentType: "+ contentType); - var message = new Object(); - message.from = callerLogin; - message.to = to; - message.body = body; - message.contentType = contentType; - message.deliveryNotification = flashphonerLoader.imdnEnabled; - messenger.sendMessage(message); -} - - -function answer(callId) { - trace("Phone - answer "+ callId); - var hasAccess; - if (isVideoCall()){ - hasAccess = hasAccessToAudioAndVideo; - } else { - hasAccess = hasAccessToAudio; - } - if (!hasAccess()) { - if (intervalId == -1) { - intervalId = setInterval('if (isVideoCall() ? hasAccessToAudioAndVideo() : hasAccessToAudio()){flashphoner_UI.closeRequestUnmute(); clearInterval(intervalId); intervalId = -1; answer(currentCall.id);}', 500); - } - if (isVideoCall()){ - flashphoner_UI.getAccessToAudioAndVideo(); - } else { - flashphoner_UI.getAccessToAudio(); - } - } else if (hasAccess()) { - flashphoner.answer(callId, isVideoCall()); - flashphonerListener.onAnswer(callId); - } else { - openConnectingView("Microphone is not plugged in", 3000); - } -} - -function hangup(callId) { - trace("Phone - hangup "+ callId); - flashphoner.hangup(callId); - flashphonerListener.onHangup(); -} - -function sendDTMF(callId, dtmf) { - trace("Phone - sendDTMF callId: "+ callId +" dtmf: "+ dtmf); - flashphoner.sendDTMF(callId, dtmf); -} - -function setStatusHold(callId, isHold) { - trace("Phone - setStatusHold callId: "+ callId+" isHold: "+ isHold); - flashphoner.setStatusHold(callId, isHold); - disableHoldButton(); -} - -function transfer(callId, target) { - trace("Phone - transfer callId: "+ callId+" target: "+ target); - flashphoner.transfer(callId, target); -} - -function hasAccessToAudioAndVideo() { - return hasAccessToAudio() && hasAccessToVideo(); -} - -function hasAccessToAudio() { - return flashphoner.hasAccessToAudio(); -} - -function hasAccessToVideo() { - return flashphoner.hasAccessToVideo(); -} - - -function sendVideoChangeState() { - trace("Phone - sendVideoChangeState currentCall: "+currentCall.id); - var sendVideoButton = getElement('sendVideo'); - if (sendVideoButton.value == 'Send video') { - sendVideoButton.value = "Stop video"; - flashphoner.setSendVideo(currentCall.id, true); - } else { - sendVideoButton.value = "Send video"; - flashphoner.setSendVideo(currentCall.id, false); - } -} - -function changeRelationMyVideo(relation) { - trace("Phone - changeRelationMyVideo "+ relation); - flashphoner.changeRelationMyVideo(relation); -} - -function getMicVolume() { - var ret = flashphoner.getMicVolume(); - trace("Phone - getMicVolume "+ret); - return ret; -} -function getVolume() { - var ret = flashphoner.getVolume(); - trace("Phone - getVolume "+ret); - return ret; -} - -function setCookie(key, value) { - trace("Phone - setCookie key: "+ key+" value: "+ value); - flashphoner.setCookie(key, value); -} - -function getCookie(key) { - trace("Phone - getCookie "+ key); - return flashphoner.getCookie(key); -} - -function getVersion() { - var ret = flashphoner.getVersion(); - trace("Phone - getVersion "+ret); - return ret; -} -/* ------------------ Notify functions ----------------- */ - -function addLogMessage(message) { - trace("Phone - addLogMessage: "+message); -} - -function notifyFlashNotFound() { - closeConnectingView(); - getElement('phoneScreen2').innerHTML = "Get Adobe Flash player"; -} - -function notifyConfigLoaded() { - notifyReady(); - flashphoner = flashphonerLoader.getFlashphoner(); - flashphoner_UI = flashphonerLoader.getFlashphonerUI(); - flashphonerListener = flashphonerLoader.getFlashphonerListener(); - messenger = new Messenger(flashphoner); - if (flashphonerLoader.useWebRTC) { - $('#micButton').css('visibility', 'hidden'); - $('#sendVideo').css('visibility', 'hidden'); - } else { - $('#micButton').css('visibility', 'visible'); - $('#sendVideo').css('visibility', 'visible'); - } - //todo refactoring - //$('#versionOfProduct').html(getVersion()); - if (flashphonerLoader.getToken()) { - loginByToken(flashphonerLoader.getToken()); - } else { - closeConnectingView(); - } -} - -function notifyRequestUnmuteResult(accessGranted) { - console.log("Access to microphone granted: " + accessGranted); -} - - -function notifyRegisterRequired(registerR) { - registerRequired = registerR; -} - -function notifyCloseConnection() { - trace("Phone - notifyCloseConnection"); - currentCall = null; - toLogOffState(); - toCallState(); - isLogged = false; - closeIncomingView(); - closeVideoView(); - closeCallView(); - getElement('sendVideo').value = "Send video"; -} - -function notifyConnected() { - trace("Phone - notifyConnected"); - if (registerRequired) { - if (!connectingViewBeClosed) { - openConnectingView("Waiting for registering...", 0); - } - } else { - toLogState(); - callerLogin = getInfoAboutMe().login; - getElement("callerLogin").innerHTML = callerLogin; - isLogged = true; - closeConnectingView(); - } - //You can set speex quality here - //flashphoner.setSpeexQuality(10); -} - -function notifyRegistered(sipObject) { - trace("Phone - notifyRegistered "+sipObject.message.raw); - if (registerRequired) { - toLogState(); - callerLogin = getInfoAboutMe().login; - getElement("callerLogin").innerHTML = callerLogin; - isLogged = true; - connectingViewBeClosed = true; - closeConnectingView(); - flashphoner.playSound("REGISTER"); - flashphonerListener.onRegistered(); - } - - if (flashphonerLoader.subscribeEvent != null && flashphonerLoader.subscribeEvent.length != 0) { - subscribeReg(); - } - - sendXcapRequest(); -} - -function notifySubscription(subscriptionObject, sipObject) { - trace("Phone - notify subscription event: " + subscriptionObject.event + " expires: " + subscriptionObject.expires + " status: " + subscriptionObject.status+" terminate: "+subscriptionObject.terminate); - trace("Phone - notify subscription body: " + subscriptionObject.requestBody); - if (subscriptionObject.event == "reg") { - if (subscriptionObject.terminate){ - terminate(); - } - } -} - -function terminate() { - trace("Phone - terminate and logoff"); - logoff(); -} - -function sendXcapRequest() { - if (flashphonerLoader.xcapUrl != null && flashphonerLoader.xcapUrl.length != 0) { - flashphoner.sendXcapRequest(flashphonerLoader.xcapUrl); - } - -} - -function notifyXcapResponse(xcapResponse) { - trace("Phone - notifyXcapResponse " + xcapResponse); - var xml = $.parseXML(xcapResponse); - var history = $(xml).find("history-list").find("history"); - if (history != null && history.length != 0) { - if (flashphonerLoader.msrpCallee != null && flashphonerLoader.msrpCallee.length != 0) { - msrpCall(flashphonerLoader.msrpCallee); - } - } -} - - -function subscribeReg() { - var subscribeObj = new Object(); - subscribeObj.event = flashphonerLoader.subscribeEvent; - subscribeObj.expires = 3600; - flashphoner.subscribe(subscribeObj); -} - -function notifyBalance(balance) { -} - -function onCallFinished(){ - trace("Phone - onCallFinished"); - // if that hangup during transfer procedure? - if (holdedCall != null) { - trace("Phone - Existing holdedCall detected: "+holdedCall.id+" currentCall: "+currentCall.id); - currentCall = holdedCall; //holded call become current - holdedCall = null; //make variable null - createCallView(currentCall); - } else { - trace("Phone - no existing holdedCall. Just close call states.") - closeIncomingView(); - closeVideoView(); - toCallState(); - flashphoner.stopSound("RING"); - flashphoner.playSound("FINISH"); - } - getElement('sendVideo').value = "Send video"; - // or this just usual hangup during the call -} - -function onCurrentCallNotify(call){ - trace("Phone - onCurrentCallNotify: "+currentCall.id+" state: "+call.state); - currentCall = call; - if (call.state == STATE_FINISH) { - onCallFinished(); - } else if (call.state == STATE_HOLD) { - $('#callState').html('...Call on hold...'); - enableHoldButton(); - } else if (call.state == STATE_TALK) { - $('#callState').html('...Talking...'); - enableHoldButton(); - flashphoner.stopSound("RING"); - var sendVideoButton = getElement('sendVideo'); - if (isVideoCall() && call.state_video == "sendrecv" && sendVideoButton.value == 'Send video'){ - sendVideoChangeState(); - } - } else if (call.state == STATE_RING) { - $('#callState').html('...Ringing...'); - flashphoner.playSound("RING"); - } else if (call.state == STATE_RING_MEDIA){ - $('#callState').html('...Ringing...'); - flashphoner.stopSound("RING"); - } else if (call.state == STATE_BUSY) { - flashphoner.playSound("BUSY"); - } else if (call.state == STATE_SESSION_PROGRESS){ - $('#callState').html('...Call in Progress...'); - flashphoner.stopSound("RING"); - } -} - -function onNotCurrentCallNotify(call){ - trace("Phone - onNotCurrentCallNotify call.id: "+call.id+" holdedCall: "+holdedCall.id+" call.state: "+call.state); - if (holdedCall.id == call.id) { - if (call.state == STATE_FINISH) { - trace("It seems we received FINISH state on holdedCall. Just do null the holdedCall."); - /* that mean if - - user1 call user2 - - user2 transfer to user3 - - user3 just thinking (not answer, not hangup) - - user2 hangup during him thinking - then we delete old holded call from user1 memory - */ - holdedCall = null; - getElement('sendVideo').value = "Send video"; - } - enableHoldButton(); - } -} - -function notify(call,sipObject) { - trace("Phone - notify call id: "+ call.id+" state: "+call.state+" callee: "+call.callee+" caller: "+call.caller+" incoming: "+call.incoming+" isVideoCall: "+call.isVideoCall); - trace("Phone - currentCall.id: "+currentCall.id); - trace("Phone - sipObject: "+sipObject); - if (currentCall.id == call.id) { - onCurrentCallNotify(call); - } else { - onNotCurrentCallNotify(call); - } -} - -function notifyCallbackHold(call, isHold) { - trace("Phone - notifyCallbackHold call: "+ call +" isHold: "+ isHold); - if (currentCall != null && currentCall.id == call.id) { - currentCall = call; - if (needOpenTransferView) { - getElement('transfer').style.visibility = "visible"; - } - if (isHold) { - getElement('holdButton').style.background = "url(assets/unhold.png)"; - $('#holdButton').unbind('click'); - $('#holdButton').click(function () { - setStatusHold(call.id, false); - }); - - } else { - getElement('holdButton').style.background = "url(assets/hold.png)"; - $('#holdButton').unbind('click'); - $('#holdButton').click(function () { - setStatusHold(call.id, true); - }); - } - } -} - -function notifyCost(cost) { -} - -function notifyBugReport(filename) { - trace("Created bug report; filename - " + filename); -} - -function notifyError(error) { - - trace("Phone - notifyError "+ error); - - if (error == CONNECTION_ERROR) { - openInfoView("Can`t connect to server.", 3000, 30); - - } else if (error == AUTHENTICATION_FAIL) { - openInfoView("Register fail, please check your SIP account details.", 3000, 30); - window.setTimeout("logoff();", 3000); - - } else if (error == USER_NOT_AVAILABLE) { - openInfoView("User not available.", 3000, 30); - - /* Deprecated error - - else if (error == TOO_MANY_REGISTER_ATTEMPTS) { - openInfoView("Connection error", 3000, 30); - toLoggedOffState(); - */ - - } else if (error == LICENSE_RESTRICTION) { - openInfoView("You trying to connect too many users, or license is expired", 3000, 90); - - } else if (error == LICENSE_NOT_FOUND) { - openInfoView("Please get a valid license or contact Flashphoner support", 5000, 90); - - } else if (error == INTERNAL_SIP_ERROR) { - openInfoView("Unknown error. Please contact support.", 3000, 60); - - } else if (error == REGISTER_EXPIRE) { - openInfoView("No response from VOIP server during 15 seconds.", 3000, 60); - - } else if (error == SIP_PORTS_BUSY) { - openInfoView("SIP ports are busy. Please open SIP ports range (30000-31000 by default).", 3000, 90); - connectingViewBeClosed = true; - window.setTimeout("logoff();", 3000); - - } else if (error == MEDIA_PORTS_BUSY) { - openInfoView("Media ports are busy. Please open media ports range (31001-32000 by default).", 3000, 90); - - } else if (error == WRONG_SIPPROVIDER_ADDRESS) { - openInfoView("Wrong domain.", 3000, 30); - connectingViewBeClosed = true; - window.setTimeout("logoff();", 3000); - - } else if (error == CALLEE_NAME_IS_NULL) { - openInfoView("Callee name is empty.", 3000, 30); - - } else if (error == WRONG_FLASHPHONER_XML) { - openInfoView("Flashphoner.xml has errors. Please check it.", 3000, 60); - } else if (error == PAYMENT_REQUIRED) { - openInfoView("Payment required, please check your balance.", 3000, 60); - } - - flashphonerListener.onError(); - closeConnectingView(); - toCallState(); -} - -function notifyVideoFormat(call) { - trace("Phone - notifyVideoFormat "+ call); - - if (call.streamerVideoWidth != 0) { - proportionStreamer = call.streamerVideoHeight / call.streamerVideoWidth; - if (proportionStreamer != 0) { - changeRelationMyVideo(proportionStreamer); - } - } - - if (!call.playerVideoHeight == 0) { //that mean if user really send me video - proportion = call.playerVideoHeight / call.playerVideoWidth; //set proportion of video picture, else it will be = 0 - } - - if ($('div').is('.videoDiv') && proportion != 0) { //if video window opened and other side send video - var newHeight = $('.videoDiv').width() * proportion + 40; - $('.videoDiv').height(newHeight); //we resize video window for new proportion - $('#video').height(newHeight - 40); //and resize flash for new video window - } -} - -function notifyOpenVideoView(isViewed) { - trace("Phone - notifyOpenVideoView "+ isViewed); - if (isViewed) { - openVideoView(); - } else { - closeVideoView(); - } -} - -function notifyMessageReceived(messageObject) { - //ignore application/im-iscomposing+xml RFC3994 - if (messageObject.contentType == "application/im-iscomposing+xml") { - return; - } - openChatView(); - trace("Phone - notifyMessageReceived "+ messageObject); - var from = messageObject.from.toLowerCase(); - createChat(from); - var chatDiv = $('#chat' + removeNonDigitOrLetter(from) + ' .chatTextarea'); //set current textarea - var body = convertMessageBody(messageObject.body, messageObject.contentType); - addMessageToChat(chatDiv, from, body, "yourNick", messageObject.id); -} - -function convertMessageBody(messageBody, contentType) { - trace("Phone - convertMessageBody " + contentType); - if (contentType == "application/fsservice+xml") { - var missedCallNotification; - var xml = $.parseXML(messageBody); - var fsService = $(xml).find("fs-services").find("fs-service"); - var action = fsService.attr("action"); - if (action == "servicenoti-indicate") { - var caw = parseMsn(fsService,"caw"); - if (!!caw){ - missedCallNotification = caw; - }else{ - missedCallNotification = parseMsn(fsService,"mcn"); - } - } else if (action == "serviceinfo-confirm") { - //service status confirmation - missedCallNotification = "Service status: " + $(fsService.find("mcn").find("mcn-data")).attr("status"); - } - if(missedCallNotification !== undefined) return missedCallNotification; - } - - return messageBody; - -} - -function parseMsn(fsService,mcn){ - trace("Phone - parseMcn: "+mcn); - var caw = fsService.find(mcn); - var ret = null; - if (!!caw){ - var cawData = caw.find(mcn+"-data"); - if (!!cawData) { - var sender = $(cawData).attr("sender"); - if (!!sender){ - trace("Phone - Missed call: " + sender); - ret = "Missed call from " + sender; - } - } - } - return ret; -} - -function addMessageToChat(chatDiv, from, body, className, messageId) { - trace("Phone - addMessageToChat: messageId: "+messageId+" from: "+from); - var idAttr = (messageId != null) ? "id='" + messageId + "'" : ""; - var isScrolled = (chatDiv[0].scrollHeight - chatDiv.height() + 1) / (chatDiv[0].scrollTop + 1); // is chat scrolled down? or may be you are reading previous messages. - var messageDiv = "
" + from + " " + body + "
"; - chatDiv.append(messageDiv); //add message to chat - if (isScrolled == 1) { - chatDiv[0].scrollTop = chatDiv[0].scrollHeight; //autoscroll if you are not reading previous messages - } -} - -function notifyMessageSent(messageObject) { - trace("Phone - notifyMessageSent "+ messageObject); - createChat(messageObject.to.toLowerCase()); - var chatDiv = $('#chat' + removeNonDigitOrLetter(messageObject.to.toLowerCase()) + ' .chatTextarea'); //set current textarea for - addMessageToChat(chatDiv, messageObject.from, messageObject.body, "myNick", messageObject.id); -} - -function notifyMessageAccepted(message) { - trace("Phone - notifyMessageAccepted "+ message); - var messageDiv = $('#' + message.id); - messageDiv.addClass("myNick message_accepted"); -} - -function notifyMessageDelivered(message) { - trace("Phone - notifyMessageDelivered "+ message); - var messageDiv = $('#' + message.id); - messageDiv.addClass("myNick message_delivered"); -} - -function notifyMessageDeliveryFailed(message) { - trace("Phone - notifyMessageDeliveryFailed "+ message); - var messageDiv = $('#' + message.id); - messageDiv.addClass("myNick message_delivery_failed"); - messageDiv.innerHTML = messageDiv.innerHTML + "- Delivery failed to " + message.recipients; -} - -function notifyMessageFailed(message) { - trace("Phone - notifyMessageFailed "+ message); - var messageDiv = $('#' + message.id); - messageDiv.addClass("myNick message_failed"); -} - -function notifyAddCall(call) { - trace("Phone - notifyAddCall "+ call.id+" call.incoming: "+call.incoming+" call.state: "+call.state); - if (currentCall!=null && !call.incoming){ - holdedCall = currentCall; - currentCall = call; - createCallView(currentCall); - trace("Phone - It seems like a hold: holdedCall: "+holdedCall.id+" currentCall: "+currentCall.id); - } else { - currentCall = call; - createCallView(currentCall); - if (call.incoming == true) { - openIncomingView(call); - toHangupState(); - flashphonerListener.onIncomingCall(call.id); - } - trace("Phone - It seems like a new call currentCall: "+currentCall.id +" state: "+currentCall.state); - } -} - -function createCallView(call) { - trace("createCallView call: "+call.id+" state: "+call.state); - openCallView(); - $('#caller').html(call.anotherSideUser); - - if (call.state == STATE_HOLD) { - $('#callState').html('...Call on hold...'); - enableHoldButton(); - } else if (call.state == STATE_TALK) { - $('#callState').html('...Talking...'); - enableHoldButton(); - } else if (call.state == STATE_RING) { - $('#callState').html('...Ringing...'); - } - - $('#holdButton').unbind('click'); - $('#holdButton').click(function () { - setStatusHold(call.id, true); - }); - - $('#transferButton').unbind('click'); - $('#transferButton').click(function () { - openTransferView(); - }); -} - -function removeCallView(call) { - closeCallView(); - $('#caller').html(''); - $('#callState').html(''); - $('#holdButton').css('background', 'url(assets/hold.png)'); -} - -function isCurrentCall(call) { - return currentCall != null && currentCall.id == call.id; -} - -function notifyRemoveCall(call) { - trace("Phone - notifyRemoveCall "+ call.id+" currentCall: "+currentCall.id); - if (isCurrentCall(call)) { - currentCall = null; - removeCallView(call) - flashphonerListener.onRemoveCall(); - } -} - -function notifyVersion(version) { - getElement('versionOfProduct').innerHTML = version; -} -/* ----------------------------------------------------------------------- */ - -/* --------------- Additional functions ------------------- */ - -function toLogState() { - trace("Phone - toLogState"); - $("#callerLogin").show().html(callerLogin); - $("#loginMainButton").hide(); -} - -function toLogOffState() { - trace("Phone - toLogOffState"); - $("#loginMainButton").show(); - $('#callerLogin').hide().html(''); -} - -function toHangupState() { - trace("Phone - toHangupState"); - $('#callButton').html("Hangup"); - /*$('#callButton').css('background', '#C00');*/ - $('#callButton').removeClass('call').addClass('hangup'); - disableCallButton(); -} - -function toCallState() { - trace("Phone - toCallState"); - $('#callButton').html("Call"); - /*$('#callButton').css('background', '#090');*/ - $('#callButton').removeClass('hangup').addClass('call'); - disableCallButton(); -} - -function disableCallButton() { - trace("Phone - disableCallButton"); - $('#callButton').addClass('disabled'); - window.setTimeout(enableCallButton, 3000); - - function enableCallButton() { - $('#callButton').removeClass('disabled'); - } -} - - -function enableHoldButton() { - trace("Phone - enableHoldButton"); - var button = $('#holdButton'); - button.css('visibility', 'inherit'); -} - -function disableHoldButton() { - trace("Phone - disableHoldButton"); - var button = $('#holdButton'); - button.css('visibility', 'hidden'); -} - - -function openLoginView() { - if (flashphonerLoader.getToken()) { - loginByToken(flashphonerLoader.getToken()); - } else { - trace("Phone - openLoginView"); - $('#loginDiv').css('visibility', 'visible'); - $('#username').val(getCookie('login')); - $('#authname').val(getCookie('authName')); - $('#password').val(getCookie('pwd')); - $('#domain').val(getCookie('domain')); - $('#outbound_proxy').val(getCookie('outbound_proxy')); - $('#port').val(getCookie('port')); - } - -} - -function closeLoginView() { - $('#loginDiv').css('visibility', 'hidden'); -} - -function openConnectingView(str, timeout) { - trace("Phone - openConnectingView: message - " + str + "; timeout - " + timeout); - if (timeout != 0) { - window.setTimeout("closeConnectingView();", timeout); - } - getElement('connectingDiv').style.visibility = "visible"; - getElement('connectingText').innerHTML = str; -} - -function closeConnectingView() { - trace("Phone - closeConnectingView"); - getElement('connectingDiv').style.visibility = "hidden"; -} - -function openInfoView(str, timeout, height) { - trace("Phone - openInfoView str: "+ str+" timeout: "+ timeout); - if (timeout != 0) { - window.setTimeout("closeInfoView();", timeout); - } - getElement('infoDiv').style.visibility = "visible"; - getElement('infoDiv').style.height = height + "px"; - getElement('infoText').innerHTML = str; -} - -function closeInfoView(timeout) { - trace("Phone - closeInfoView "+timeout); - if (timeout) { - window.setTimeout("getElement('infoDiv').style.visibility = 'hidden';", timeout); - } else { - getElement('infoDiv').style.visibility = "hidden"; - } -} - -function openIncomingView(call) { - trace("Phone - openIncomingView "+ call)// call.caller, call.visibleNameCaller - - //form Caller-ID information displayed to user - var displayedCaller = ""; - if (call.caller !== undefined) displayedCaller += call.caller; - if (call.visibleNameCaller !== undefined) displayedCaller += " '" + call.visibleNameCaller + "'"; - - $('#incomingDiv').show(); - $('#callerField').html(displayedCaller); - - $('#answerButton').unbind('click'); - $('#answerButton').click(function () { - answer(call.id); - closeIncomingView(); - }); - $('#hangupButton').unbind('click'); - $('#hangupButton').click(function () { - trace("Phone - openIncomingView hangup "+call.id); - hangup(call.id); - closeIncomingView(); - }); -} - -function closeIncomingView() { - trace("Phone - closeIncomingView"); - $('#incomingDiv').hide(); -} - -function openSettingsView() { - trace("Phone - openSettingsView"); - getElement('settingsDiv').style.visibility = "visible"; -} -function closeSettingsView() { - trace("Phone - closeSettingsView"); - getElement('settingsDiv').style.visibility = "hidden"; -} - -function getElement(str) { - return document.getElementById(str); -} - -/* ----- VIDEO ----- */ - -function openVideoView() { - flashphoner_UI.openVideoView(); -} - -function closeVideoView() { - trace("Phone - closeVideoView"); - $('#video_requestUnmuteDiv').removeClass().addClass('closed'); -} - -/* ----- CHAT ----- */ - -function openChatView() { - trace("Phone - openChatView"); - $('#chatDiv').css('visibility', 'visible'); -} -function closeChatView() { - trace("Phone - closeChatView"); - $('#chatDiv').css('visibility', 'hidden'); -} -/*-----------------*/ - -/* ----- CALL ----- */ -function openCallView() { - trace("Phone - openCallView"); - $('#callDiv').css('visibility', 'visible'); -} -function closeCallView() { - trace("Phone - closeCallView"); - $('#callDiv').css('visibility', 'hidden'); -} -/*-----------------*/ -/* ----- TRANSFER ----- */ -function openTransferView() { - trace("Phone - openTransferView"); - $('#transferOk').unbind('click'); - $('#transferOk').click(function () { - if (currentCall.state == STATE_HOLD) { - transfer(currentCall.id, $('#transferInput').val()); - closeTransferView(); - } else { - needOpenTransferView = true; - setStatusHold(currentCall.id, true); - } - }); - - if (call.state != STATE_HOLD) { - needOpenTransferView = true; - setStatusHold(currentCall.id, true); - } else { - getElement('transfer').style.visibility = "visible"; - } -} - -function closeTransferView() { - trace("Phone - closeTransferView"); - needOpenTransferView = false; - getElement('transfer').style.visibility = "hidden"; -} - -function submitBugReport(){ - var bugReportText = getElement('bugReportText').value; - trace("submitBugReport "+bugReportText); - if (flashphoner){ - flashphoner.submitBugReport({text:bugReportText, type: "no_media"}); - } -} - -/*-----------------*/ - -/* ------------- Additional interface functions --------- */ -function isVideoCall(){ - return $('#checkboxVideoCall').attr("checked") ? true : false; -} -// Functions createChat creates chat with the callee. -// It contains all chat window functionality including send message function - -function createChat(calleeName) { - - //var closetab = '×'; - //$("#tabul").append('
  • ' + calleeName + ' ' + closetab + '
  • '); //add tab with the close button - var shortCalleeName = calleeName; - var fullCalleeName = shortCalleeName; - var calleeNameId = removeNonDigitOrLetter(fullCalleeName); - if (!$('li').is('#tab' + calleeNameId)) { - var closetab = '×'; - - // We will cut too long calleeNames to place it within chat tab - if (shortCalleeName.length > 21) { - shortCalleeName = shortCalleeName.substr(0, 21) + '...'; - } - - - $("#tabul").append('
  • ' + shortCalleeName + ' ' + closetab + '
  • '); //add tab with the close button - - - $('#tabcontent').append('
    '); //add chatBox - $('#chat' + calleeNameId).append('
    ')//add text area for chat messages - .append('')//add input field - .append(''); //add send button - - $("#tabul li").removeClass("ctab"); //remove select from all tabs - $("#tab" + calleeNameId).addClass("ctab"); //select new tab - $(".chatBox").hide(); //hide all chatBoxes - $("#chat" + calleeNameId).show(); //show new chatBox - - // Bind send message on click Enter in message inout field - - $('#chat' + calleeNameId + ' .messageInput').keydown(function (event) { - if (event.keyCode == '13') { - $(this).next().click(); // click on sendMessage button - } else if (event.keyCode == '27') { - $(this).val(''); - } - }); - - // Bind send message function - $('#chat' + calleeNameId + ' .messageSend').click(function () { - var fullCalleeName = $(this).parent().attr('fullCalleeName'); //parse id of current chatBox, take away chat word from the beginning - var messageText = $(this).prev().val(); //parse text from input - sendMessage(calleeName, messageText, flashphonerLoader.msgContentType); //send message - $(this).prev().val(''); //clear message input - }); - - // Bind selecting tab - $("#tab" + calleeNameId).bind("click", function () { - $("#tabul li").removeClass("ctab"); //hide all tabs - $("#tab" + calleeNameId).addClass("ctab"); //select clicked tab - $(".chatBox").hide(); //chide all chatBoxes - $("#chat" + calleeNameId).show(); //show new chatBox - }); - - // Bind closing tab on click - $("#close" + calleeNameId).click(function () { - //close this tab - $(this).parent().hide(); - $("#chat" + calleeNameId).hide(); - - var prevVisibleTab = $(this).parent().prevAll().filter(':visible').filter(':first'); //set prev visible tab - var nextVisibleTab = $(this).parent().nextAll().filter(':visible').filter(':first'); //set next visible tab - - if ($(this).parent().is('.ctab')) { //but what if this tab was selected? - $(this).parent().removeClass("ctab"); //we will unselect this - if (prevVisibleTab.is('.ntabs')) { //and if there is prev tab - prevVisibleTab.addClass('ctab'); //then select prev tab - $('#chat' + prevVisibleTab.attr('id').substr(3)).show(); //and show accoring chat - - } else if (nextVisibleTab.is('.ntabs')) { //or if there is next tab - nextVisibleTab.addClass('ctab'); //then select next tab - $('#chat' + nextVisibleTab.attr('id').substr(3)).show(); //and show accoring chat - - } else { - $('#chatDiv').css('visibility', 'hidden'); //else simply close all chat - } - } - ; - return false; // i don`t know why it need - }); - } else { - $("#tabul li").removeClass("ctab"); //remove select from all tabs - $("#tab" + calleeNameId).show(); //show our tab - $("#tab" + calleeNameId).addClass("ctab"); //select our tab - $(".chatBox").hide(); //hide all chatboxes - $("#chat" + calleeNameId).show(); //show our chatBox - - } - -} - -function removeNonDigitOrLetter(calleeName) { - return calleeName.replace(/\W/g, '') -} - -/* ---------------------------------------------------- */ - -// functions closeView is simplifying of many close....View functions -function close(element) { - element.css('visibility', 'hidden'); -} - - -/* --------------------- On document load we do... ------------------ */ -function notifyReady() { - - // open login view - $("#loginMainButton").click(function () { - openLoginView(); - }); - - // logout - $("#logoutButton").click(function () { - logoff(); - $(this).hide(); - }); - - // login - $("#loginButton").click(function () { - login(); - }); - - // click on caller login show logout button - $("#callerLogin").click(function () { - $('#logoutButton').toggle() - }); - - // every time when we change callee field - we set parameter callee - // that parameter used around the code - $("#calleeText").keyup(function () { - callee = $(this).val(); - }); - - //Bind click on different buttons - $("#callButton").click(function () { - if ($("#callButton").html() == 'Call') { - call(); - } else { - if (currentCall) { - trace("Phone - Hangup current call by click: "+currentCall.id); - hangup(currentCall.id); - } else { - trace("Phone - Hangup call by click"); - hangup(); - } - } - }); - - $("#cameraButtonInCallee").click(function () { - openVideoView(); - }); - - $("#canselLoginDiv").click(function () { - closeLoginView(); - }); - - $("#sendVideo").click(function () { - sendVideoChangeState(); - }); - - $("#transferCansel").click(function () { - closeTransferView(); - }); - - $(".iconButton").click(function () { - $(this).toggleClass('iconPressed'); - }); - - //micButton opens mic slider - $("#micButton").click(function () { - if ($(this).hasClass('iconPressed')) { - $('#micSlider').show(); - $('#micBack').show(); - } else { - $('#micSlider').hide(); - $('#micBack').hide(); - } - }); - - //micButton opens mic slider - $("#soundButton").click(function () { - if ($(this).hasClass('iconPressed')) { - $('#speakerSlider').show(); - $('#speakerBack').show(); - } else { - $('#speakerSlider').hide(); - $('#speakerBack').hide(); - } - }); - - $("#cameraButton").click(function () { - openVideoView(); - }); - - $("#closeButton_video_requestUnmuteDiv").click(function () { - closeVideoView(); - }); - - $(".closeButton").click(function () { - close($(this).parent()); - }); - - //enable drag and resize objects - $("#loginDiv").draggable({handle: '.bar', stack: "#loginDiv"}); - $("#incomingDiv").draggable({handle: '.bar', stack: "#incomingDiv"}); - $("#settingsDiv").draggable({handle: '.bar', stack: "#settingsDiv"}); - $("#transfer").draggable({handle: '.bar', stack: "#transfer"}); - $("#chatDiv").draggable({handle: '.bar', stack: "#chatDiv"}); - $("#video_requestUnmuteDiv").draggable({handle: '.bar', stack: "#video_requestUnmuteDiv"}); - $("#video_requestUnmuteDiv").resizable({ minWidth: 215, minHeight: 180, aspectRatio: true}); - - var all_videos = $('#localVideoPreview, #remoteVideo'); - all_videos.each(function () { - var el = $(this); - el.attr('data-aspectRatio', el.height() / el.width()); - var width = $("#video_requestUnmuteDiv").width(); - el.attr('data-windowRatio', el.width() / (width == 1 ? 640 : width)); - }); - - $("#video_requestUnmuteDiv").resize(function () { - var width = $("#video_requestUnmuteDiv").width(); - var height = $("#video_requestUnmuteDiv").height(); - var newWidth = width == 1 ? 640 : width; - $('#video').height((height == 1 ? 520 : height) - 40); - $('#video').width(width == 1 ? 640 : width); - $('#remoteVideo').height((height == 1 ? 520 : height) - 40); - var localVideo = $('#localVideoPreview'); - localVideo.height(newWidth * localVideo.attr('data-windowRatio') * localVideo.attr('data-aspectRatio')); - all_videos.each(function () { - var el = $(this); - el.width(newWidth * el.attr('data-windowRatio')); - }); - }).resize(); - - //Bind click on number buttons - $(".numberButton").click(function () { - if (currentCall != null && currentCall.state == STATE_TALK) { - sendDTMF(currentCall.id, $(this).html()); - } else if (currentCall == null) { - $("#calleeText").val($("#calleeText").val() + $(this).html()); - callee = callee + $(this).html(); - } - }); - - $(".testButton").click(function () { - startUnitTests(); - }); - - $(".bugReportButton").click(function () { - submitBugReport(); - }); - - // this function set changing in button styles when you press any button - $(".button").mousedown(function () { - $(this).addClass('pressed'); - }).mouseup(function () { - $(this).removeClass('pressed'); - }).mouseout(function () { - $(this).removeClass('pressed'); - }); - - // Bind click on chatButton - $("#chatButton").click(function () { - if (isLogged) { - if (callee != '') { - openChatView(); - createChat(callee.toLowerCase()); - } else { - openConnectingView("Callee number is wrong", 3000); - } - } else { - openLoginView(); - } - }); - - /* Autofill Aut. name field when you fill Login field */ - $('#username').keyup(function () { - $('#authname').val($(this).val()); - }); - - /* Autofill Outb. proxy field when you fill "domain" field */ - $('#domain').keyup(function () { - $('#outbound_proxy').val($(this).val()); - }); - - // Mic slider set mic volume when you slide it - $("#micSlider").slider({ - orientation: "vertical", - range: "min", - min: 0, - max: 100, - value: 60, - slide: function (event, ui) { - flashphoner.setMicVolume(ui.value); - } - }); - - // Speaker slider set speaker volume when you slide it - $("#speakerSlider").slider({ - orientation: "vertical", - range: "min", - min: 0, - max: 100, - value: 60, - slide: function (event, ui) { - flashphoner.setVolume(ui.value); - } - }); - - $("#checkboxUseProxy").change(function () { - if ($(this).attr("checked")) { - flashphoner.setUseProxy(true); - } else { - flashphoner.setUseProxy(false); - } - }); - - -}; diff --git a/client/client/src/js/StaticData.js b/client/client/src/js/StaticData.js deleted file mode 100644 index d5a309b4..00000000 --- a/client/client/src/js/StaticData.js +++ /dev/null @@ -1,102 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -var STATE_RING = "RING"; -var STATE_RING_MEDIA = "RING_MEDIA"; -var STATE_HOLD = "HOLD"; -var STATE_TALK = "TALK"; -var STATE_FINISH = "FINISH"; -var STATE_BUSY = "BUSY"; -var STATE_SESSION_PROGRESS = "SESSION_PROGRESS"; - -var AUTHENTICATION_FAIL = "AUTHENTICATION_FAIL"; -var USER_NOT_AVAILABLE = "USER_NOT_AVAILABLE"; -var TOO_MANY_REGISTER_ATTEMPTS = "TOO_MANY_REGISTER_ATTEMPTS"; -var LICENSE_RESTRICTION = "LICENSE_RESTRICTION"; -var LICENSE_NOT_FOUND = "LICENSE_NOT_FOUND"; -var INTERNAL_SIP_ERROR = "INTERNAL_SIP_ERROR"; -var CONNECTION_ERROR = "CONNECTION_ERROR"; -var REGISTER_EXPIRE = "REGISTER_EXPIRE"; -var SIP_PORTS_BUSY = "SIP_PORTS_BUSY"; -var MEDIA_PORTS_BUSY = "MEDIA_PORTS_BUSY"; -var WRONG_SIPPROVIDER_ADDRESS = "WRONG_SIPPROVIDER_ADDRESS"; -var CALLEE_NAME_IS_NULL = "CALLEE_NAME_IS_NULL"; -var WRONG_FLASHPHONER_XML = "WRONG_FLASHPHONER_XML"; -var PAYMENT_REQUIRED = "PAYMENT_REQUIRED"; - -function extend(Child, Parent) { - var F = function() { } - F.prototype = Parent.prototype - Child.prototype = new F() - Child.prototype.constructor = Child - Child.superclass = Parent.prototype -} - -function trace(logMessage) { - - var today = new Date(); - // get hours, minutes and seconds - var hh = today.getUTCHours().toString(); - var mm = today.getUTCMinutes().toString(); - var ss = today.getUTCSeconds().toString(); - var ms = today.getUTCMilliseconds().toString(); - - // Add leading '0' to see 14:08:06.001 instead of 14:8:6.1 - hh = hh.length == 1 ? "0" + hh : hh; - mm = mm.length == 1 ? "0" + mm : mm; - ss = ss.length == 1 ? "0" + ss : ss; - ms = ms.length == 1 ? "00" + ms : ms.length == 2 ? "0" + ms : ms; - - // set time - var time = "UTC " + hh + ':' + mm + ':' + ss + '.' + ms; - - var console = $("#console"); - - // Check if console is scrolled down? Or may be you are reading previous messages. - var isScrolled = (console[0].scrollHeight - console.height() + 1) / (console[0].scrollTop + 1 + 37); - - var logMessage = time + ' - ' + logMessage; - - // Print message to console and push it to server - if (traceEnabled) { - //check if API already loaded - if (flashphoner !== undefined) { - //check if push_log enabled - if (flashphonerLoader.pushLogEnabled) { - var result = flashphoner.pushLogs(logs + logMessage+'\n'); - if (!result) { - logs += logMessage+'\n'; - } else { - logs = ""; - } - } else { - logs = ""; - } - - } else { - logs += logMessage+'\n'; - } - - console.append(logMessage+'
    '); - try { - window.console.debug(logMessage); - } catch(err) { - //Not supported. For example IE - } - - } - - //Autoscroll cosole if you are not reading previous messages - if (isScrolled < 1) { - console[0].scrollTop = console[0].scrollHeight; - } -} \ No newline at end of file diff --git a/client/client/src/js/UnitTests.js b/client/client/src/js/UnitTests.js deleted file mode 100644 index a4476bd0..00000000 --- a/client/client/src/js/UnitTests.js +++ /dev/null @@ -1,11 +0,0 @@ -function startUnitTests() { - testConvertMessageBody(); -} - -function testConvertMessageBody(){ - //var messageBody=""; - var messageBody="" - var contentType="application/fsservice+xml"; - var res = convertMessageBody(messageBody,contentType); - trace("Phone - testConvertMessageBody "+res); -} \ No newline at end of file diff --git a/client/client/src/js/imgtrackbar/b_bg_all.gif b/client/client/src/js/imgtrackbar/b_bg_all.gif deleted file mode 100644 index 20751aa7..00000000 Binary files a/client/client/src/js/imgtrackbar/b_bg_all.gif and /dev/null differ diff --git a/client/client/src/js/imgtrackbar/b_bg_off.gif b/client/client/src/js/imgtrackbar/b_bg_off.gif deleted file mode 100644 index 9087f866..00000000 Binary files a/client/client/src/js/imgtrackbar/b_bg_off.gif and /dev/null differ diff --git a/client/client/src/js/imgtrackbar/b_bg_on.gif b/client/client/src/js/imgtrackbar/b_bg_on.gif deleted file mode 100644 index 002497ab..00000000 Binary files a/client/client/src/js/imgtrackbar/b_bg_on.gif and /dev/null differ diff --git a/client/client/src/js/imgtrackbar/b_l.gif b/client/client/src/js/imgtrackbar/b_l.gif deleted file mode 100644 index bcbe5f43..00000000 Binary files a/client/client/src/js/imgtrackbar/b_l.gif and /dev/null differ diff --git a/client/client/src/js/imgtrackbar/b_r.gif b/client/client/src/js/imgtrackbar/b_r.gif deleted file mode 100644 index 7867a92a..00000000 Binary files a/client/client/src/js/imgtrackbar/b_r.gif and /dev/null differ diff --git a/client/client/src/js/jquery/jquery.js b/client/client/src/js/jquery/jquery.js deleted file mode 100644 index f3201aac..00000000 --- a/client/client/src/js/jquery/jquery.js +++ /dev/null @@ -1,8981 +0,0 @@ -/*! - * jQuery JavaScript Library v1.6.2 - * http://jquery.com/ - * - * Copyright 2011, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Jun 30 14:16:56 2011 -0400 - */ -(function( window, undefined ) { - -// Use the correct document accordingly with window argument (sandbox) -var document = window.document, - navigator = window.navigator, - location = window.location; -var jQuery = (function() { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - trimLeft = /^\s+/, - trimRight = /\s+$/, - - // Check for digits - rdigit = /\d/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, - rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - - // Useragent RegExp - rwebkit = /(webkit)[ \/]([\w.]+)/, - ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, - rmsie = /(msie) ([\w.]+)/, - rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, - - // Matches dashed string for camelizing - rdashAlpha = /-([a-z])/ig, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // The deferred used on DOM ready - readyList, - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - trim = String.prototype.trim, - indexOf = Array.prototype.indexOf, - - // [[Class]] -> type pairs - class2type = {}; - -jQuery.fn = jQuery.prototype = { - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context && document.body ) { - this.context = document; - this[0] = document.body; - this.selector = selector; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = quickExpr.exec( selector ); - } - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - doc = (context ? context.ownerDocument || context : document); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if (selector.selector !== undefined) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.6.2", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = this.constructor(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // Add the callback - readyList.done( fn ); - - return this; - }, - - eq: function( i ) { - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - // Either a released hold or an DOMready/load event and not yet ready - if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 1 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger( "ready" ).unbind( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyList ) { - return; - } - - readyList = jQuery._Deferred(); - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", DOMContentLoaded ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - // A crude way of determining if an object is a window - isWindow: function( obj ) { - return obj && typeof obj === "object" && "setInterval" in obj; - }, - - isNaN: function( obj ) { - return obj == null || !rdigit.test( obj ) || isNaN( obj ); - }, - - type: function( obj ) { - return obj == null ? - String( obj ) : - class2type[ toString.call(obj) ] || "object"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call(obj, "constructor") && - !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return (new Function( "return " + data ))(); - - } - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - // (xml & tmp used internally) - parseXML: function( data , xml , tmp ) { - - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - - tmp = xml.documentElement; - - if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) { - jQuery.error( "Invalid XML: " + data ); - } - - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && rnotwhite.test( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Converts a dashed string to camelCased string; - // Used by both the css and data modules - camelCase: function( string ) { - return string.replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction( object ); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { - break; - } - } - } - } - - return object; - }, - - // Use native String.trim function wherever possible - trim: trim ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type( array ); - - if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( elem, array ) { - - if ( indexOf ) { - return indexOf.call( array, elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; - }, - - merge: function( first, second ) { - var i = first.length, - j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = [], retVal; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, key, ret = [], - i = 0, - length = elems.length, - // jquery objects are treated as arrays - isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - if ( typeof context === "string" ) { - var tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - var args = slice.call( arguments, 2 ), - proxy = function() { - return fn.apply( context, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - - return proxy; - }, - - // Mutifunctional method to get and set values to a collection - // The value/s can optionally be executed if it's a function - access: function( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - jQuery.access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; - }, - - now: function() { - return (new Date()).getTime(); - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = rwebkit.exec( ua ) || - ropera.exec( ua ) || - rmsie.exec( ua ) || - ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - sub: function() { - function jQuerySub( selector, context ) { - return new jQuerySub.fn.init( selector, context ); - } - jQuery.extend( true, jQuerySub, this ); - jQuerySub.superclass = this; - jQuerySub.fn = jQuerySub.prototype = this(); - jQuerySub.fn.constructor = jQuerySub; - jQuerySub.sub = this.sub; - jQuerySub.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { - context = jQuerySub( context ); - } - - return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); - }; - jQuerySub.fn.init.prototype = jQuerySub.fn; - var rootjQuerySub = jQuerySub(document); - return jQuerySub; - }, - - browser: {} -}); - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -// IE doesn't match non-breaking spaces with \s -if ( rnotwhite.test( "\xA0" ) ) { - trimLeft = /^[\s\xA0]+/; - trimRight = /[\s\xA0]+$/; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch(e) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -return jQuery; - -})(); - - -var // Promise methods - promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ), - // Static reference to slice - sliceDeferred = [].slice; - -jQuery.extend({ - // Create a simple deferred (one callbacks list) - _Deferred: function() { - var // callbacks list - callbacks = [], - // stored [ context , args ] - fired, - // to avoid firing when already doing so - firing, - // flag to know if the deferred has been cancelled - cancelled, - // the deferred itself - deferred = { - - // done( f1, f2, ...) - done: function() { - if ( !cancelled ) { - var args = arguments, - i, - length, - elem, - type, - _fired; - if ( fired ) { - _fired = fired; - fired = 0; - } - for ( i = 0, length = args.length; i < length; i++ ) { - elem = args[ i ]; - type = jQuery.type( elem ); - if ( type === "array" ) { - deferred.done.apply( deferred, elem ); - } else if ( type === "function" ) { - callbacks.push( elem ); - } - } - if ( _fired ) { - deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); - } - } - return this; - }, - - // resolve with given context and args - resolveWith: function( context, args ) { - if ( !cancelled && !fired && !firing ) { - // make sure args are available (#8421) - args = args || []; - firing = 1; - try { - while( callbacks[ 0 ] ) { - callbacks.shift().apply( context, args ); - } - } - finally { - fired = [ context, args ]; - firing = 0; - } - } - return this; - }, - - // resolve with this as context and given arguments - resolve: function() { - deferred.resolveWith( this, arguments ); - return this; - }, - - // Has this deferred been resolved? - isResolved: function() { - return !!( firing || fired ); - }, - - // Cancel - cancel: function() { - cancelled = 1; - callbacks = []; - return this; - } - }; - - return deferred; - }, - - // Full fledged deferred (two callbacks list) - Deferred: function( func ) { - var deferred = jQuery._Deferred(), - failDeferred = jQuery._Deferred(), - promise; - // Add errorDeferred methods, then and promise - jQuery.extend( deferred, { - then: function( doneCallbacks, failCallbacks ) { - deferred.done( doneCallbacks ).fail( failCallbacks ); - return this; - }, - always: function() { - return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); - }, - fail: failDeferred.done, - rejectWith: failDeferred.resolveWith, - reject: failDeferred.resolve, - isRejected: failDeferred.isResolved, - pipe: function( fnDone, fnFail ) { - return jQuery.Deferred(function( newDefer ) { - jQuery.each( { - done: [ fnDone, "resolve" ], - fail: [ fnFail, "reject" ] - }, function( handler, data ) { - var fn = data[ 0 ], - action = data[ 1 ], - returned; - if ( jQuery.isFunction( fn ) ) { - deferred[ handler ](function() { - returned = fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise().then( newDefer.resolve, newDefer.reject ); - } else { - newDefer[ action ]( returned ); - } - }); - } else { - deferred[ handler ]( newDefer[ action ] ); - } - }); - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - if ( obj == null ) { - if ( promise ) { - return promise; - } - promise = obj = {}; - } - var i = promiseMethods.length; - while( i-- ) { - obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ]; - } - return obj; - } - }); - // Make sure only one callback list will be used - deferred.done( failDeferred.cancel ).fail( deferred.cancel ); - // Unexpose cancel - delete deferred.cancel; - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - return deferred; - }, - - // Deferred helper - when: function( firstParam ) { - var args = arguments, - i = 0, - length = args.length, - count = length, - deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? - firstParam : - jQuery.Deferred(); - function resolveFunc( i ) { - return function( value ) { - args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; - if ( !( --count ) ) { - // Strange bug in FF4: - // Values changed onto the arguments object sometimes end up as undefined values - // outside the $.when method. Cloning the object into a fresh array solves the issue - deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) ); - } - }; - } - if ( length > 1 ) { - for( ; i < length; i++ ) { - if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) { - args[ i ].promise().then( resolveFunc(i), deferred.reject ); - } else { - --count; - } - } - if ( !count ) { - deferred.resolveWith( deferred, args ); - } - } else if ( deferred !== firstParam ) { - deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); - } - return deferred.promise(); - } -}); - - - -jQuery.support = (function() { - - var div = document.createElement( "div" ), - documentElement = document.documentElement, - all, - a, - select, - opt, - input, - marginDiv, - support, - fragment, - body, - testElementParent, - testElement, - testElementStyle, - tds, - events, - eventName, - i, - isSupported; - - // Preliminary tests - div.setAttribute("className", "t"); - div.innerHTML = "
    a"; - - all = div.getElementsByTagName( "*" ); - a = div.getElementsByTagName( "a" )[ 0 ]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return {}; - } - - // First batch of supports tests - select = document.createElement( "select" ); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName( "input" )[ 0 ]; - - support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: ( div.firstChild.nodeType === 3 ), - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName( "tbody" ).length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName( "link" ).length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: ( input.value === "on" ), - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // Will be defined later - submitBubbles: true, - changeBubbles: true, - focusinBubbles: false, - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent( "onclick", function() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - support.noCloneEvent = false; - }); - div.cloneNode( true ).fireEvent( "onclick" ); - } - - // Check if a radio maintains it's value - // after being appended to the DOM - input = document.createElement("input"); - input.value = "t"; - input.setAttribute("type", "radio"); - support.radioValue = input.value === "t"; - - input.setAttribute("checked", "checked"); - div.appendChild( input ); - fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - div.innerHTML = ""; - - // Figure out if the W3C box model works as expected - div.style.width = div.style.paddingLeft = "1px"; - - body = document.getElementsByTagName( "body" )[ 0 ]; - // We use our own, invisible, body unless the body is already present - // in which case we use a div (#9239) - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0 - }; - if ( body ) { - jQuery.extend( testElementStyle, { - position: "absolute", - left: -1000, - top: -1000 - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - support.boxModel = div.offsetWidth === 2; - - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); - - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
    "; - support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); - } - - div.innerHTML = "
    t
    "; - tds = div.getElementsByTagName( "td" ); - - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - div.innerHTML = ""; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( document.defaultView && document.defaultView.getComputedStyle ) { - marginDiv = document.createElement( "div" ); - marginDiv.style.width = "0"; - marginDiv.style.marginRight = "0"; - div.appendChild( marginDiv ); - support.reliableMarginRight = - ( parseInt( ( document.defaultView.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; - } - - // Remove the body element we added - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); - - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( div.attachEvent ) { - for( i in { - submit: 1, - change: 1, - focusin: 1 - } ) { - eventName = "on" + i; - isSupported = ( eventName in div ); - if ( !isSupported ) { - div.setAttribute( eventName, "return;" ); - isSupported = ( typeof div[ eventName ] === "function" ); - } - support[ i + "Bubbles" ] = isSupported; - } - } - - // Null connected elements to avoid leaks in IE - testElement = fragment = select = opt = body = marginDiv = div = input = null; - - return support; -})(); - -// Keep track of boxModel -jQuery.boxModel = jQuery.support.boxModel; - - - - -var rbrace = /^(?:\{.*\}|\[.*\])$/, - rmultiDash = /([a-z])([A-Z])/g; - -jQuery.extend({ - cache: {}, - - // Please use with caution - uuid: 0, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache, - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ jQuery.expando ] = id = ++jQuery.uuid; - } else { - id = jQuery.expando; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name); - } else { - cache[ id ] = jQuery.extend(cache[ id ], name); - } - } - - thisCache = cache[ id ]; - - // Internal jQuery data is stored in a separate object inside the object's data - // cache in order to avoid key collisions between internal data and user-defined - // data - if ( pvt ) { - if ( !thisCache[ internalKey ] ) { - thisCache[ internalKey ] = {}; - } - - thisCache = thisCache[ internalKey ]; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should - // not attempt to inspect the internal events object using jQuery.data, as this - // internal data object is undocumented and subject to change. - if ( name === "events" && !thisCache[name] ) { - return thisCache[ internalKey ] && thisCache[ internalKey ].events; - } - - return getByName ? - // Check for both converted-to-camel and non-converted data property names - thisCache[ jQuery.camelCase( name ) ] || thisCache[ name ] : - thisCache; - }, - - removeData: function( elem, name, pvt /* Internal Use Only */ ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var internalKey = jQuery.expando, isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - - // See jQuery.data for more information - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ]; - - if ( thisCache ) { - delete thisCache[ name ]; - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !isEmptyDataObject(thisCache) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( pvt ) { - delete cache[ id ][ internalKey ]; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject(cache[ id ]) ) { - return; - } - } - - var internalCache = cache[ id ][ internalKey ]; - - // Browsers that fail expando deletion also refuse to delete expandos on - // the window, but it will allow it on all other JS objects; other browsers - // don't care - if ( jQuery.support.deleteExpando || cache != window ) { - delete cache[ id ]; - } else { - cache[ id ] = null; - } - - // We destroyed the entire user cache at once because it's faster than - // iterating through each key, but we need to continue to persist internal - // data if it existed - if ( internalCache ) { - cache[ id ] = {}; - // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery - // metadata on plain JS objects when the object is serialized using - // JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - - cache[ id ][ internalKey ] = internalCache; - - // Otherwise, we need to eliminate the expando on the node to avoid - // false lookups in the cache for entries that no longer exist - } else if ( isNode ) { - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; - } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); - } else { - elem[ jQuery.expando ] = null; - } - } - }, - - // For internal use only. - _data: function( elem, name, data ) { - return jQuery.data( elem, name, data, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - if ( elem.nodeName ) { - var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; - - if ( match ) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - - return true; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var data = null; - - if ( typeof key === "undefined" ) { - if ( this.length ) { - data = jQuery.data( this[0] ); - - if ( this[0].nodeType === 1 ) { - var attr = this[0].attributes, name; - for ( var i = 0, l = attr.length; i < l; i++ ) { - name = attr[i].name; - - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.substring(5) ); - - dataAttr( this[0], name, data[ name ] ); - } - } - } - } - - return data; - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - // Try to fetch any internally stored data first - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - data = dataAttr( this[0], key, data ); - } - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - - } else { - return this.each(function() { - var $this = jQuery( this ), - args = [ parts[0], value ]; - - $this.triggerHandler( "setData" + parts[1] + "!", args ); - jQuery.data( this, key, value ); - $this.triggerHandler( "changeData" + parts[1] + "!", args ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - var name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - !jQuery.isNaN( data ) ? parseFloat( data ) : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON -// property to be considered empty objects; this property always exists in -// order to make sure JSON.stringify does not expose internal metadata -function isEmptyDataObject( obj ) { - for ( var name in obj ) { - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - - - - -function handleQueueMarkDefer( elem, type, src ) { - var deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - defer = jQuery.data( elem, deferDataKey, undefined, true ); - if ( defer && - ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) && - ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) { - // Give room for hard-coded callbacks to fire first - // and eventually mark/queue something else on the element - setTimeout( function() { - if ( !jQuery.data( elem, queueDataKey, undefined, true ) && - !jQuery.data( elem, markDataKey, undefined, true ) ) { - jQuery.removeData( elem, deferDataKey, true ); - defer.resolve(); - } - }, 0 ); - } -} - -jQuery.extend({ - - _mark: function( elem, type ) { - if ( elem ) { - type = (type || "fx") + "mark"; - jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true ); - } - }, - - _unmark: function( force, elem, type ) { - if ( force !== true ) { - type = elem; - elem = force; - force = false; - } - if ( elem ) { - type = type || "fx"; - var key = type + "mark", - count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 ); - if ( count ) { - jQuery.data( elem, key, count, true ); - } else { - jQuery.removeData( elem, key, true ); - handleQueueMarkDefer( elem, type, "mark" ); - } - } - }, - - queue: function( elem, type, data ) { - if ( elem ) { - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type, undefined, true ); - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data), true ); - } else { - q.push( data ); - } - } - return q || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - fn = queue.shift(), - defer; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift("inprogress"); - } - - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); - } - - if ( !queue.length ) { - jQuery.removeData( elem, type + "queue", true ); - handleQueueMarkDefer( elem, type, "queue" ); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function() { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; - - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, object ) { - if ( typeof type !== "string" ) { - object = type; - type = undefined; - } - type = type || "fx"; - var defer = jQuery.Deferred(), - elements = this, - i = elements.length, - count = 1, - deferDataKey = type + "defer", - queueDataKey = type + "queue", - markDataKey = type + "mark", - tmp; - function resolve() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - } - while( i-- ) { - if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || - ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || - jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && - jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { - count++; - tmp.done( resolve ); - } - } - resolve(); - return defer.promise(); - } -}); - - - - -var rclass = /[\n\t\r]/g, - rspace = /\s+/, - rreturn = /\r/g, - rtype = /^(?:button|input)$/i, - rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - rinvalidChar = /\:|^on/, - formHook, boolHook; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, name, value, true, jQuery.prop ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classNames, i, l, elem, - setClass, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call(this, j, this.className) ); - }); - } - - if ( value && typeof value === "string" ) { - classNames = value.split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className && classNames.length === 1 ) { - elem.className = value; - - } else { - setClass = " " + elem.className + " "; - - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { - setClass += classNames[ c ] + " "; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classNames, i, l, elem, className, c, cl; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call(this, j, this.className) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - classNames = (value || "").split( rspace ); - - for ( i = 0, l = this.length; i < l; i++ ) { - elem = this[ i ]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - className = (" " + elem.className + " ").replace( rclass, " " ); - for ( c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[ c ] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space seperated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var hooks, ret, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return undefined; - } - - var isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var self = jQuery(this), val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, - index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && - (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attrFix: { - // Always normalize to ensure hook usage - tabindex: "tabIndex" - }, - - attr: function( elem, name, value, pass ) { - var nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery( elem )[ name ]( value ); - } - - // Fallback to prop when attributes are not supported - if ( !("getAttribute" in elem) ) { - return jQuery.prop( elem, name, value ); - } - - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // Normalize the name if needed - if ( notxml ) { - name = jQuery.attrFix[ name ] || name; - - hooks = jQuery.attrHooks[ name ]; - - if ( !hooks ) { - // Use boolHook for boolean attributes - if ( rboolean.test( name ) ) { - - hooks = boolHook; - - // Use formHook for forms and if the name contains certain characters - } else if ( formHook && name !== "className" && - (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) { - - hooks = formHook; - } - } - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return undefined; - - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, "" + value ); - return value; - } - - } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - ret = elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return ret === null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, name ) { - var propName; - if ( elem.nodeType === 1 ) { - name = jQuery.attrFix[ name ] || name; - - if ( jQuery.support.getSetAttribute ) { - // Use removeAttribute in browsers that support it - elem.removeAttribute( name ); - } else { - jQuery.attr( elem, name, "" ); - elem.removeAttributeNode( elem.getAttributeNode( name ) ); - } - - // Set corresponding property to false for boolean attributes - if ( rboolean.test( name ) && (propName = jQuery.propFix[ name ] || name) in elem ) { - elem[ propName ] = false; - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to it's default in case type is set after value - // This is for element creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - }, - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabIndex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - }, - // Use the value property for back compat - // Use the formHook for button elements in IE6/7 (#1954) - value: { - get: function( elem, name ) { - if ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.get( elem, name ); - } - return name in elem ? - elem.value : - null; - }, - set: function( elem, value, name ) { - if ( formHook && jQuery.nodeName( elem, "button" ) ) { - return formHook.set( elem, value, name ); - } - // Does not return so that setAttribute is also used - elem.value = value; - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return undefined; - } - - var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return (elem[ name ] = value); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: {} -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - // Align boolean attributes with corresponding properties - return jQuery.prop( elem, name ) ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - var propName; - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - // value is true since we know at this point it's type boolean and not false - // Set boolean attributes to the same name and set the DOM property - propName = jQuery.propFix[ name ] || name; - if ( propName in elem ) { - // Only set the IDL specifically if it already exists on the element - elem[ propName ] = true; - } - - elem.setAttribute( name, name.toLowerCase() ); - } - return name; - } -}; - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !jQuery.support.getSetAttribute ) { - - // propFix is more comprehensive and contains all fixes - jQuery.attrFix = jQuery.propFix; - - // Use this for any attribute on a form in IE6/7 - formHook = jQuery.attrHooks.name = jQuery.attrHooks.title = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret; - ret = elem.getAttributeNode( name ); - // Return undefined if nodeValue is empty string - return ret && ret.nodeValue !== "" ? - ret.nodeValue : - undefined; - }, - set: function( elem, value, name ) { - // Check form objects in IE (multiple bugs related) - // Only use nodeValue if the attribute node exists on the form - var ret = elem.getAttributeNode( name ); - if ( ret ) { - ret.nodeValue = value; - return value; - } - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); -} - - -// Some attributes require a special call on IE -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret === null ? undefined : ret; - } - }); - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Normalize to lowercase since IE uppercases css property names - return elem.style.cssText.toLowerCase() || undefined; - }, - set: function( elem, value ) { - return (elem.style.cssText = "" + value); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }); -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0); - } - } - }); -}); - - - - -var rnamespaces = /\.(.*)$/, - rformElems = /^(?:textarea|input|select)$/i, - rperiod = /\./g, - rspaces = / /g, - rescape = /[^\w\s.|`]/g, - fcleanup = function( nm ) { - return nm.replace(rescape, "\\$&"); - }; - -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - if ( handler === false ) { - handler = returnFalse; - } else if ( !handler ) { - // Fixes bug #7229. Fix recommended by jdalton - return; - } - - var handleObjIn, handleObj; - - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - } - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure - var elemData = jQuery._data( elem ); - - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { - return; - } - - var events = elemData.events, - eventHandle = elemData.handle; - - if ( !events ) { - elemData.events = events = {}; - } - - if ( !eventHandle ) { - elemData.handle = eventHandle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : - undefined; - }; - } - - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); - - var type, i = 0, namespaces; - - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; - - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); - - } else { - namespaces = []; - handleObj.namespace = ""; - } - - handleObj.type = type; - if ( !handleObj.guid ) { - handleObj.guid = handler.guid; - } - - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; - - // Init the event handler queue - if ( !handlers ) { - handlers = events[ type ] = []; - - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add the function to the element's handler list - handlers.push( handleObj ); - - // Keep track of which events have been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - if ( handler === false ) { - handler = returnFalse; - } - - var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ), - events = elemData && elemData.events; - - if ( !elemData || !events ) { - return; - } - - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } - } - - continue; - } - - special = jQuery.event.special[ type ] || {}; - - for ( j = pos || 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } - - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - - if ( pos != null ) { - break; - } - } - } - - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - ret = null; - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem, undefined, true ); - } - } - }, - - // Events that are safe to short-circuit if no handlers are attached. - // Native DOM events should not be added, they may have inline handlers. - customEvent: { - "getData": true, - "setData": true, - "changeData": true - }, - - trigger: function( event, data, elem, onlyHandlers ) { - // Event object or event type - var type = event.type || event, - namespaces = [], - exclusive; - - if ( type.indexOf("!") >= 0 ) { - // Exclusive events trigger only for the exact event (no namespaces) - type = type.slice(0, -1); - exclusive = true; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - - if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { - // No jQuery handlers for this event type, and it can't have inline handlers - return; - } - - // Caller can pass in an Event, Object, or just an event type string - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - new jQuery.Event( type, event ) : - // Just the event type (string) - new jQuery.Event( type ); - - event.type = type; - event.exclusive = exclusive; - event.namespace = namespaces.join("."); - event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); - - // triggerHandler() and global events don't bubble or run the default action - if ( onlyHandlers || !elem ) { - event.preventDefault(); - event.stopPropagation(); - } - - // Handle a global trigger - if ( !elem ) { - // TODO: Stop taunting the data cache; remove global events and always attach to document - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); - return; - } - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // Clean up the event in case it is being reused - event.result = undefined; - event.target = elem; - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data != null ? jQuery.makeArray( data ) : []; - data.unshift( event ); - - var cur = elem, - // IE doesn't like method names with a colon (#3533, #8272) - ontype = type.indexOf(":") < 0 ? "on" + type : ""; - - // Fire event on the current element, then bubble up the DOM tree - do { - var handle = jQuery._data( cur, "handle" ); - - event.currentTarget = cur; - if ( handle ) { - handle.apply( cur, data ); - } - - // Trigger an inline bound script - if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { - event.result = false; - event.preventDefault(); - } - - // Bubble up to document, then to window - cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; - } while ( cur && !event.isPropagationStopped() ); - - // If nobody prevented the default action, do it now - if ( !event.isDefaultPrevented() ) { - var old, - special = jQuery.event.special[ type ] || {}; - - if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction)() check here because IE6/7 fails that test. - // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch. - try { - if ( ontype && elem[ type ] ) { - // Don't re-trigger an onFOO event when we call its FOO() method - old = elem[ ontype ]; - - if ( old ) { - elem[ ontype ] = null; - } - - jQuery.event.triggered = type; - elem[ type ](); - } - } catch ( ieError ) {} - - if ( old ) { - elem[ ontype ] = old; - } - - jQuery.event.triggered = undefined; - } - } - - return event.result; - }, - - handle: function( event ) { - event = jQuery.event.fix( event || window.event ); - // Snapshot the handlers list since a called handler may add/remove events. - var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), - run_all = !event.exclusive && !event.namespace, - args = Array.prototype.slice.call( arguments, 0 ); - - // Use the fix-ed Event rather than the (read-only) native event - args[0] = event; - event.currentTarget = this; - - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Triggered event must 1) be non-exclusive and have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event. - if ( run_all || event.namespace_re.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, args ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - return event.result; - }, - - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; - event = jQuery.Event( originalEvent ); - - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary - if ( !event.target ) { - // Fixes #1925 where srcElement might not be defined either - event.target = event.srcElement || document; - } - - // check if target is a textnode (safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var eventDocument = event.target.ownerDocument || document, - doc = eventDocument.documentElement, - body = eventDocument.body; - - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( event.which == null && (event.charCode != null || event.keyCode != null) ) { - event.which = event.charCode != null ? event.charCode : event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { - event.metaKey = event.ctrlKey; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; - }, - - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop - }, - - live: { - add: function( handleObj ) { - jQuery.event.add( this, - liveConvert( handleObj.origType, handleObj.selector ), - jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) ); - }, - - remove: function( handleObj ) { - jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj ); - } - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( jQuery.isWindow( this ) ) { - this.onbeforeunload = eventHandle; - } - }, - - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - if ( elem.detachEvent ) { - elem.detachEvent( "on" + type, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // otherwise set the returnValue property of the original event to false (IE) - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - - // Check if mouse(over|out) are still within the same parent element - var related = event.relatedTarget, - inside = false, - eventType = event.type; - - event.type = event.data; - - if ( related !== this ) { - - if ( related ) { - inside = jQuery.contains( this, related ); - } - - if ( !inside ) { - - jQuery.event.handle.apply( this, arguments ); - - event.type = eventType; - } - } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); - } - }; -}); - -// submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( !jQuery.nodeName( this, "form" ) ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, - type = elem.type; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - trigger( "submit", this, arguments ); - } - }); - - } else { - return false; - } - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); - } - }; - -} - -// change delegation, happens here so we have bind. -if ( !jQuery.support.changeBubbles ) { - - var changeFilters, - - getVal = function( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( jQuery.nodeName( elem, "select" ) ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery._data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery._data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - e.liveFired = undefined; - jQuery.event.trigger( e, arguments[1], elem ); - } - }; - - jQuery.event.special.change = { - filters: { - focusout: testChange, - - beforedeactivate: testChange, - - click: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - - if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) { - testChange.call( this, e ); - } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : ""; - - if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information - beforeactivate: function( e ) { - var elem = e.target; - jQuery._data( elem, "_change_data", getVal(elem) ); - } - }, - - setup: function( data, namespaces ) { - if ( this.type === "file" ) { - return false; - } - - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } - - return rformElems.test( this.nodeName ); - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); - - return rformElems.test( this.nodeName ); - } - }; - - changeFilters = jQuery.event.special.change.filters; - - // Handle when the input is .focus()'d - changeFilters.focus = changeFilters.beforeactivate; -} - -function trigger( type, elem, args ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - // Don't pass args or remember liveFired; they apply to the donor event. - var event = jQuery.extend( {}, args[ 0 ] ); - event.type = type; - event.originalEvent = {}; - event.liveFired = undefined; - jQuery.event.handle.call( elem, event ); - if ( event.isDefaultPrevented() ) { - args[ 0 ].preventDefault(); - } -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - - function handler( donor ) { - // Donor event is always a native one; fix it and switch its type. - // Let focusin/out handler cancel the donor focus/blur event. - var e = jQuery.event.fix( donor ); - e.type = fix; - e.originalEvent = {}; - jQuery.event.trigger( e, null, e.target ); - if ( e.isDefaultPrevented() ) { - donor.preventDefault(); - } - } - }); -} - -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - var handler; - - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); - } - return this; - } - - if ( arguments.length === 2 || data === false ) { - fn = data; - data = undefined; - } - - if ( name === "one" ) { - handler = function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }; - handler.guid = fn.guid || jQuery.guid++; - } else { - handler = fn; - } - - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); - } - } - - return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); - } - } - - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); - }, - - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - - triggerHandler: function( type, data ) { - if ( this[0] ) { - return jQuery.event.trigger( type, data, this[0], true ); - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, - guid = fn.guid || jQuery.guid++, - i = 0, - toggler = function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - }; - - // link all the functions, so any of them can unbind this click handler - toggler.guid = guid; - while ( i < args.length ) { - args[ i++ ].guid = guid; - } - - return this.click( toggler ); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( typeof types === "object" && !types.preventDefault ) { - for ( var key in types ) { - context[ name ]( key, data, types[key], selector ); - } - - return this; - } - - if ( name === "die" && !types && - origSelector && origSelector.charAt(0) === "." ) { - - context.unbind( origSelector ); - - return this; - } - - if ( data === false || jQuery.isFunction( data ) ) { - fn = data || returnFalse; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( liveMap[ type ] ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - for ( var j = 0, l = context.length; j < l; j++ ) { - jQuery.event.add( context[j], "live." + liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - } - - } else { - // unbind live handler - context.unbind( "live." + liveConvert( type, selector ), fn ); - } - } - - return this; - }; -}); - -function liveHandler( event ) { - var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret, - elems = [], - selectors = [], - events = jQuery._data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911) - if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) { - return; - } - - if ( event.namespace ) { - namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - close = match[i]; - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) { - elem = close.elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - event.type = handleObj.preType; - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - - // Make sure not to accidentally match a child element with the same selector - if ( related && jQuery.contains( elem, related ) ) { - related = elem; - } - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj, level: close.level }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - - if ( maxLevel && match.level > maxLevel ) { - break; - } - - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - ret = match.handleObj.origHandler.apply( match.elem, arguments ); - - if ( ret === false || event.isPropagationStopped() ) { - maxLevel = match.level; - - if ( ret === false ) { - stop = false; - } - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&"); -} - -jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup error").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - if ( fn == null ) { - fn = data; - data = null; - } - - return arguments.length > 0 ? - this.bind( name, data, fn ) : - this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } -}); - - - -/*! - * Sizzle CSS Selector Engine - * Copyright 2011, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true, - rBackslash = /\\/g, - rNonWord = /\W/; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparision -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function() { - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function( selector, context, results, seed ) { - results = results || []; - context = context || document; - - var origContext = context; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var m, set, checkSet, extra, ret, cur, pop, i, - prune = true, - contextXML = Sizzle.isXML( context ), - parts = [], - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - do { - chunker.exec( "" ); - m = chunker.exec( soFar ); - - if ( m ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - } while ( m ); - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set ); - } - } - - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - - ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? - Sizzle.filter( ret.expr, ret.set )[0] : - ret.set[0]; - } - - if ( context ) { - ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - - set = ret.expr ? - Sizzle.filter( ret.expr, ret.set ) : - ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray( set ); - - } else { - prune = false; - } - - while ( parts.length ) { - cur = parts.pop(); - pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - - } else if ( context && context.nodeType === 1 ) { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - - } else { - for ( i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function( results ) { - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[ i - 1 ] ) { - results.splice( i--, 1 ); - } - } - } - } - - return results; -}; - -Sizzle.matches = function( expr, set ) { - return Sizzle( expr, null, null, set ); -}; - -Sizzle.matchesSelector = function( node, expr ) { - return Sizzle( expr, null, null, [node] ).length > 0; -}; - -Sizzle.find = function( expr, context, isXML ) { - var set; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var match, - type = Expr.order[i]; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice( 1, 1 ); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace( rBackslash, "" ); - set = Expr.find[ type ]( match, context, isXML ); - - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( "*" ) : - []; - } - - return { set: set, expr: expr }; -}; - -Sizzle.filter = function( expr, set, inplace, not ) { - var match, anyFound, - old = expr, - result = [], - curLoop = set, - isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var found, item, - filter = Expr.filter[ type ], - left = match[1]; - - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - - } else { - curLoop[i] = false; - } - - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - - match: { - ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - - leftMatch: {}, - - attrMap: { - "class": "className", - "for": "htmlFor" - }, - - attrHandle: { - href: function( elem ) { - return elem.getAttribute( "href" ); - }, - type: function( elem ) { - return elem.getAttribute( "type" ); - } - }, - - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !rNonWord.test( part ), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - - ">": function( checkSet, part ) { - var elem, - isPartStr = typeof part === "string", - i = 0, - l = checkSet.length; - - if ( isPartStr && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - - } else { - for ( ; i < l; i++ ) { - elem = checkSet[i]; - - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - - "": function(checkSet, part, isXML){ - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); - }, - - "~": function( checkSet, part, isXML ) { - var nodeCheck, - doneName = done++, - checkFn = dirCheck; - - if ( typeof part === "string" && !rNonWord.test( part ) ) { - part = part.toLowerCase(); - nodeCheck = part; - checkFn = dirNodeCheck; - } - - checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); - } - }, - - find: { - ID: function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }, - - NAME: function( match, context ) { - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], - results = context.getElementsByName( match[1] ); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - - TAG: function( match, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( match[1] ); - } - } - }, - preFilter: { - CLASS: function( match, curLoop, inplace, result, not, isXML ) { - match = " " + match[1].replace( rBackslash, "" ) + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - - ID: function( match ) { - return match[1].replace( rBackslash, "" ); - }, - - TAG: function( match, curLoop ) { - return match[1].replace( rBackslash, "" ).toLowerCase(); - }, - - CHILD: function( match ) { - if ( match[1] === "nth" ) { - if ( !match[2] ) { - Sizzle.error( match[0] ); - } - - match[2] = match[2].replace(/^\+|\s*/g, ''); - - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - else if ( match[2] ) { - Sizzle.error( match[0] ); - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - - ATTR: function( match, curLoop, inplace, result, not, isXML ) { - var name = match[1] = match[1].replace( rBackslash, "" ); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - // Handle if an un-quoted value was used - match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - - PSEUDO: function( match, curLoop, inplace, result, not ) { - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - - if ( !inplace ) { - result.push.apply( result, ret ); - } - - return false; - } - - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - - POS: function( match ) { - match.unshift( true ); - - return match; - } - }, - - filters: { - enabled: function( elem ) { - return elem.disabled === false && elem.type !== "hidden"; - }, - - disabled: function( elem ) { - return elem.disabled === true; - }, - - checked: function( elem ) { - return elem.checked === true; - }, - - selected: function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - parent: function( elem ) { - return !!elem.firstChild; - }, - - empty: function( elem ) { - return !elem.firstChild; - }, - - has: function( elem, i, match ) { - return !!Sizzle( match[3], elem ).length; - }, - - header: function( elem ) { - return (/h\d/i).test( elem.nodeName ); - }, - - text: function( elem ) { - var attr = elem.getAttribute( "type" ), type = elem.type; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); - }, - - radio: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; - }, - - checkbox: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; - }, - - file: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; - }, - - password: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; - }, - - submit: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "submit" === elem.type; - }, - - image: function( elem ) { - return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; - }, - - reset: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && "reset" === elem.type; - }, - - button: function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && "button" === elem.type || name === "button"; - }, - - input: function( elem ) { - return (/input|select|textarea|button/i).test( elem.nodeName ); - }, - - focus: function( elem ) { - return elem === elem.ownerDocument.activeElement; - } - }, - setFilters: { - first: function( elem, i ) { - return i === 0; - }, - - last: function( elem, i, match, array ) { - return i === array.length - 1; - }, - - even: function( elem, i ) { - return i % 2 === 0; - }, - - odd: function( elem, i ) { - return i % 2 === 1; - }, - - lt: function( elem, i, match ) { - return i < match[3] - 0; - }, - - gt: function( elem, i, match ) { - return i > match[3] - 0; - }, - - nth: function( elem, i, match ) { - return match[3] - 0 === i; - }, - - eq: function( elem, i, match ) { - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function( elem, match, i, array ) { - var name = match[1], - filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; - - } else if ( name === "not" ) { - var not = match[3]; - - for ( var j = 0, l = not.length; j < l; j++ ) { - if ( not[j] === elem ) { - return false; - } - } - - return true; - - } else { - Sizzle.error( name ); - } - }, - - CHILD: function( elem, match ) { - var type = match[1], - node = elem; - - switch ( type ) { - case "only": - case "first": - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - if ( type === "first" ) { - return true; - } - - node = elem; - - case "last": - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - - return true; - - case "nth": - var first = match[2], - last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - - if ( first === 0 ) { - return diff === 0; - - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - - ID: function( elem, match ) { - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - - TAG: function( elem, match ) { - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; - }, - - CLASS: function( elem, match ) { - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - - ATTR: function( elem, match ) { - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - - POS: function( elem, match, i, array ) { - var name = match[2], - filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS, - fescape = function(all, num){ - return "\\" + (num - 0 + 1); - }; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); -} - -var makeArray = function( array, results ) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch( e ) { - makeArray = function( array, results ) { - var i = 0, - ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - - } else { - if ( typeof array.length === "number" ) { - for ( var l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - - } else { - for ( ; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder, siblingCheck; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - return a.compareDocumentPosition ? -1 : 1; - } - - return a.compareDocumentPosition(b) & 4 ? -1 : 1; - }; - -} else { - sortOrder = function( a, b ) { - // The nodes are identical, we can exit early - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Fallback to using sourceIndex (in IE) if it's available on both nodes - } else if ( a.sourceIndex && b.sourceIndex ) { - return a.sourceIndex - b.sourceIndex; - } - - var al, bl, - ap = [], - bp = [], - aup = a.parentNode, - bup = b.parentNode, - cur = aup; - - // If the nodes are siblings (or identical) we can do a quick check - if ( aup === bup ) { - return siblingCheck( a, b ); - - // If no parents were found then the nodes are disconnected - } else if ( !aup ) { - return -1; - - } else if ( !bup ) { - return 1; - } - - // Otherwise they're somewhere else in the tree so we need - // to build up a full list of the parentNodes for comparison - while ( cur ) { - ap.unshift( cur ); - cur = cur.parentNode; - } - - cur = bup; - - while ( cur ) { - bp.unshift( cur ); - cur = cur.parentNode; - } - - al = ap.length; - bl = bp.length; - - // Start walking down the tree looking for a discrepancy - for ( var i = 0; i < al && i < bl; i++ ) { - if ( ap[i] !== bp[i] ) { - return siblingCheck( ap[i], bp[i] ); - } - } - - // We ended someplace up the tree so do a sibling check - return i === al ? - siblingCheck( a, bp[i], -1 ) : - siblingCheck( ap[i], b, 1 ); - }; - - siblingCheck = function( a, b, ret ) { - if ( a === b ) { - return ret; - } - - var cur = a.nextSibling; - - while ( cur ) { - if ( cur === b ) { - return -1; - } - - cur = cur.nextSibling; - } - - return 1; - }; -} - -// Utility function for retreiving the text value of an array of DOM nodes -Sizzle.getText = function( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += Sizzle.getText( elem.childNodes ); - } - } - - return ret; -}; - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date()).getTime(), - root = document.documentElement; - - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function( match, context, isXML ) { - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - - return m ? - m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? - [m] : - undefined : - []; - } - }; - - Expr.filter.ID = function( elem, match ) { - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - - // release memory in IE - root = form = null; -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function( match, context ) { - var results = context.getElementsByTagName( match[1] ); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - - Expr.attrHandle.href = function( elem ) { - return elem.getAttribute( "href", 2 ); - }; - } - - // release memory in IE - div = null; -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, - div = document.createElement("div"), - id = "__sizzle__"; - - div.innerHTML = "

    "; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function( query, context, extra, seed ) { - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && !Sizzle.isXML(context) ) { - // See if we find a selector to speed up - var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); - - if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { - // Speed-up: Sizzle("TAG") - if ( match[1] ) { - return makeArray( context.getElementsByTagName( query ), extra ); - - // Speed-up: Sizzle(".CLASS") - } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { - return makeArray( context.getElementsByClassName( match[2] ), extra ); - } - } - - if ( context.nodeType === 9 ) { - // Speed-up: Sizzle("body") - // The body element only exists once, optimize finding it - if ( query === "body" && context.body ) { - return makeArray( [ context.body ], extra ); - - // Speed-up: Sizzle("#ID") - } else if ( match && match[3] ) { - var elem = context.getElementById( match[3] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id === match[3] ) { - return makeArray( [ elem ], extra ); - } - - } else { - return makeArray( [], extra ); - } - } - - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(qsaError) {} - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - var oldContext = context, - old = context.getAttribute( "id" ), - nid = old || id, - hasParent = context.parentNode, - relativeHierarchySelector = /^\s*[+~]/.test( query ); - - if ( !old ) { - context.setAttribute( "id", nid ); - } else { - nid = nid.replace( /'/g, "\\$&" ); - } - if ( relativeHierarchySelector && hasParent ) { - context = context.parentNode; - } - - try { - if ( !relativeHierarchySelector || hasParent ) { - return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); - } - - } catch(pseudoError) { - } finally { - if ( !old ) { - oldContext.removeAttribute( "id" ); - } - } - } - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - // release memory in IE - div = null; - })(); -} - -(function(){ - var html = document.documentElement, - matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; - - if ( matches ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9 fails this) - var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), - pseudoWorks = false; - - try { - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( document.documentElement, "[test!='']:sizzle" ); - - } catch( pseudoError ) { - pseudoWorks = true; - } - - Sizzle.matchesSelector = function( node, expr ) { - // Make sure that attribute selectors are quoted - expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); - - if ( !Sizzle.isXML( node ) ) { - try { - if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { - var ret = matches.call( node, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || !disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9, so check for that - node.document && node.document.nodeType !== 11 ) { - return ret; - } - } - } catch(e) {} - } - - return Sizzle(expr, null, null, [node]).length > 0; - }; - } -})(); - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
    "; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function( match, context, isXML ) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - // release memory in IE - div = null; -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - - if ( elem ) { - var match = false; - - elem = elem[dir]; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -if ( document.documentElement.contains ) { - Sizzle.contains = function( a, b ) { - return a !== b && (a.contains ? a.contains(b) : true); - }; - -} else if ( document.documentElement.compareDocumentPosition ) { - Sizzle.contains = function( a, b ) { - return !!(a.compareDocumentPosition(b) & 16); - }; - -} else { - Sizzle.contains = function() { - return false; - }; -} - -Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function( selector, context ) { - var match, - tmpSet = [], - later = "", - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})(); - - -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - isSimple = /^.[^:#\[\.,]*$/, - slice = Array.prototype.slice, - POS = jQuery.expr.match.POS, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var self = this, - i, l; - - if ( typeof selector !== "string" ) { - return jQuery( selector ).filter(function() { - for ( i = 0, l = self.length; i < l; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }); - } - - var ret = this.pushStack( "", "find", selector ), - length, n, r; - - for ( i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( n = length; n < ret.length; n++ ) { - for ( r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && ( typeof selector === "string" ? - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var ret = [], i, l, cur = this[0]; - - // Array - if ( jQuery.isArray( selectors ) ) { - var match, selector, - matches = {}, - level = 1; - - if ( cur && selectors.length ) { - for ( i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[ selector ] ) { - matches[ selector ] = POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[ selector ]; - - if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { - ret.push({ selector: selector, elem: cur, level: level }); - } - } - - cur = cur.parentNode; - level++; - } - } - - return ret; - } - - // String - var pos = POS.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( i = 0, l = this.length; i < l; i++ ) { - cur = this[i]; - - while ( cur ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - - } else { - cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { - break; - } - } - } - } - - ret = ret.length > 1 ? jQuery.unique( ret ) : ret; - - return this.pushStack( ret, "closest", selectors ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); - } - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ), - // The variable 'args' was introduced in - // https://github.com/jquery/jquery/commit/52a0238 - // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed. - // http://code.google.com/p/v8/issues/detail?id=1050 - args = slice.call(arguments); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, args.join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; - }); -} - - - - -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rtagName = /<([\w:]+)/, - rtbody = /", "" ], - legend: [ 1, "
    ", "
    " ], - thead: [ 1, "", "
    " ], - tr: [ 2, "", "
    " ], - td: [ 3, "", "
    " ], - col: [ 2, "", "
    " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and - Hidden frame for Browser History support. - - diff --git a/client/client/src/js/swf/playerProductInstall.swf b/client/client/src/js/swf/playerProductInstall.swf deleted file mode 100644 index bdc34378..00000000 Binary files a/client/client/src/js/swf/playerProductInstall.swf and /dev/null differ diff --git a/client/client/src/js/swf/swfobject.js b/client/client/src/js/swf/swfobject.js deleted file mode 100644 index 839d82f3..00000000 --- a/client/client/src/js/swf/swfobject.js +++ /dev/null @@ -1,4 +0,0 @@ -/* SWFObject v2.2 beta1 - is released under the MIT License -*/ -var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab\ - \ -
    \ - \ -
    \ - \ - '); - // Is all right? - if (this.onMove == null) { - this.debug([1,8]); - return; - } - // --- - this.leftBegun = this.gebi(this.LEFT_BEGUN_PREFIX + this.id); - if (this.leftBegun == null) { - this.debug([1,2]); - return; - } - this.rightBegun = this.gebi(this.RIGHT_BEGUN_PREFIX + this.id); - if (this.rightBegun == null) { - this.debug([1,3]); - return; - } - this.leftBlock = this.gebi(this.LEFT_BLOCK_PREFIX + this.id); - if (this.leftBlock == null) { - this.debug([1,4]); - return; - } - this.rightBlock = this.gebi(this.RIGHT_BLOCK_PREFIX + this.id); - if (this.rightBlock == null) { - this.debug([1,5]); - return; - } - this.centerBlock = this.gebi(this.CENTER_BLOCK_PREFIX + this.id); - if (this.centerBlock == null) { - this.debug([1,9]); - return; - } - // --- - if (!this.width) { - this.debug([1,6]); - return; - } - if (!this.rightLimit) { - this.debug([1,7]); - return; - } - // Set default - this.valueWidth = this.width - 2 * this.widthRem; - this.rightValue = hash.rightValue || this.rightLimit; - this.leftValue = hash.leftValue || this.leftLimit; - if (!this.dual) this.rightValue = this.leftValue; - this.valueInterval = this.rightLimit - this.leftLimit; - this.leftWidth = parseInt((this.leftValue - this.leftLimit) / this.valueInterval * this.valueWidth) + this.widthRem; - this.rightWidth = this.valueWidth - parseInt((this.rightValue - this.leftLimit) / this.valueInterval * this.valueWidth) + this.widthRem; - // Set limits - if (!this.clearLimits) { - this.leftBlock.firstChild.nextSibling.innerHTML = this.leftLimit; - this.rightBlock.firstChild.nextSibling.innerHTML = this.rightLimit; - } - // Do it! - this.setCurrentState(); - this.onMove(); - // Add handers - var _this = this; - this.addHandler ( - document, - "mousemove", - function(evt) { - if (_this.moveState) _this.moveHandler(evt); - if (_this.moveIntervalState) _this.moveIntervalHandler(evt); - } - ); - this.addHandler ( - document, - "mouseup", - function() { - _this.moveState = false; - _this.moveIntervalState = false; - } - ); - this.addHandler ( - this.leftBegun, - "mousedown", - function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - _this.moveState = "left"; - _this.x0 = _this.defPosition(evt).x; - _this.blockX0 = _this.leftWidth; - } - ); - this.addHandler ( - this.rightBegun, - "mousedown", - function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - _this.moveState = "right"; - _this.x0 = _this.defPosition(evt).x; - _this.blockX0 = _this.rightWidth; - } - ); - this.addHandler ( - this.centerBlock, - "mousedown", - function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - _this.moveIntervalState = true; - _this.intervalWidth = _this.width - _this.rightWidth - _this.leftWidth; - _this.x0 = _this.defPosition(evt).x; - _this.rightX0 = _this.rightWidth; - _this.leftX0 = _this.leftWidth; - } - ), - this.addHandler ( - this.centerBlock, - "click", - function(evt) { - if (!_this.itWasMove) _this.clickMove(evt); - _this.itWasMove = false; - } - ); - this.addHandler ( - this.leftBlock, - "click", - function(evt) { - if (!_this.itWasMove)_this.clickMoveLeft(evt); - _this.itWasMove = false; - } - ); - this.addHandler ( - this.rightBlock, - "click", - function(evt) { - if (!_this.itWasMove)_this.clickMoveRight(evt); - _this.itWasMove = false; - } - ); - } catch(e) {this.debug([1]);} - }, - clickMoveRight : function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - var x = this.defPosition(evt).x - this.absPosition(this.rightBlock).x; - var w = this.rightBlock.offsetWidth; - if (x <= 0 || w <= 0 || w < x || (w - x) < this.widthRem) return; - this.rightWidth = (w - x); - this.rightCounter(); - - this.setCurrentState(); - this.onMove(); - }, - clickMoveLeft : function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - var x = this.defPosition(evt).x - this.absPosition(this.leftBlock).x; - var w = this.leftBlock.offsetWidth; - if (x <= 0 || w <= 0 || w < x || x < this.widthRem) return; - this.leftWidth = x; - this.leftCounter(); - - this.setCurrentState(); - this.onMove(); - }, - clickMove : function(evt) { - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - var x = this.defPosition(evt).x - this.absPosition(this.centerBlock).x; - var w = this.centerBlock.offsetWidth; - if (x <= 0 || w <= 0 || w < x) return; - if (x >= w / 2) { - this.rightWidth += (w - x); - this.rightCounter(); - } else { - this.leftWidth += x; - this.leftCounter(); - } - this.setCurrentState(); - this.onMove(); - }, - setCurrentState : function() { - this.leftBlock.style.width = this.leftWidth + "px"; - if (!this.clearValues) this.leftBlock.firstChild.innerHTML = (!this.dual && this.leftWidth > this.width / 2) ? "" : this.leftValue; - if(!this.dual) { - var x = this.leftBlock.firstChild.offsetWidth; - this.leftBlock.firstChild.style.right = (this.widthRem * (1 - 2 * (this.leftWidth - this.widthRem) / this.width) - ((this.leftWidth - this.widthRem) * x / this.width)) + 'px'; - } - this.rightBlock.style.width = this.rightWidth + "px"; - if (!this.clearValues) this.rightBlock.firstChild.innerHTML = (!this.dual && this.rightWidth >= this.width / 2) ? "" : this.rightValue; - if(!this.dual) { - var x = this.rightBlock.firstChild.offsetWidth; - this.rightBlock.firstChild.style.left = (this.widthRem * (1 - 2 * (this.rightWidth - this.widthRem) / this.width) - ((this.rightWidth - this.widthRem) * x / this.width)) + 'px'; - } - }, - /* OLD setCurrentState : function() { - this.leftBlock.style.width = this.leftWidth + "px"; - this.leftBlock.firstChild.innerHTML = (!this.dual && this.leftWidth > this.width / 2) ? "" : this.leftValue; - this.rightBlock.style.width = this.rightWidth + "px"; - this.rightBlock.firstChild.innerHTML = (!this.dual && this.rightWidth >= this.width / 2) ? "" : this.rightValue; - },*/ - moveHandler : function(evt) { - this.itWasMove = true; - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - if (this.moveState == "left") { - this.leftWidth = this.blockX0 + this.defPosition(evt).x - this.x0; - this.leftCounter(); - } - if (this.moveState == "right") { - this.rightWidth = this.blockX0 + this.x0 - this.defPosition(evt).x; - this.rightCounter(); - } - this.setCurrentState(); - this.onMove(); - }, - moveIntervalHandler : function(evt) { - this.itWasMove = true; - evt = evt || window.event; - if (evt.preventDefault) evt.preventDefault(); - evt.returnValue = false; - var dX = this.defPosition(evt).x - this.x0; - if (dX > 0) { - this.rightWidth = this.rightX0 - dX > this.widthRem ? this.rightX0 - dX : this.widthRem; - this.leftWidth = this.width - this.rightWidth - this.intervalWidth; - } else { - this.leftWidth = this.leftX0 + dX > this.widthRem ? this.leftX0 + dX : this.widthRem; - this.rightWidth = this.width - this.leftWidth - this.intervalWidth; - } - this.rightCounter(); - this.leftCounter(); - this.setCurrentState(); - this.onMove(); - }, - rightCounter : function() { - if (this.dual) { - this.rightWidth = this.rightWidth > this.width - this.leftWidth ? this.width - this.leftWidth : this.rightWidth; - this.rightWidth = this.rightWidth < this.widthRem ? this.widthRem : this.rightWidth; - this.rightValue = this.leftLimit + this.valueInterval - parseInt((this.rightWidth - this.widthRem) / this.valueWidth * this.valueInterval); - if (this.roundUp) this.rightValue = parseInt(this.rightValue / this.roundUp) * this.roundUp; - if (this.leftWidth + this.rightWidth >= this.width) this.rightValue = this.leftValue; - } else { - this.rightWidth = this.rightWidth > (this.width - this.widthRem) ? this.width - this.widthRem : this.rightWidth; - this.rightWidth = this.rightWidth < this.widthRem ? this.widthRem : this.rightWidth; - this.leftWidth = this.width - this.rightWidth; - this.rightValue = this.leftLimit + this.valueInterval - parseInt((this.rightWidth - this.widthRem) / this.valueWidth * this.valueInterval); - if (this.roundUp) this.rightValue = parseInt(this.rightValue / this.roundUp) * this.roundUp; - this.leftValue = this.rightValue; - } - }, - leftCounter : function() { - if (this.dual) { - this.leftWidth = this.leftWidth > this.width - this.rightWidth ? this.width - this.rightWidth : this.leftWidth; - this.leftWidth = this.leftWidth < this.widthRem ? this.widthRem : this.leftWidth; - this.leftValue = this.leftLimit + parseInt((this.leftWidth - this.widthRem) / this.valueWidth * this.valueInterval); - if (this.roundUp) this.leftValue = parseInt(this.leftValue / this.roundUp) * this.roundUp; - if (this.leftWidth + this.rightWidth >= this.width) this.leftValue = this.rightValue; - } else { - this.leftWidth = this.leftWidth > (this.width - this.widthRem) ? this.width - this.widthRem : this.leftWidth; - this.leftWidth = this.leftWidth < this.widthRem ? this.widthRem : this.leftWidth; - this.rightWidth = this.width - this.leftWidth; - this.leftValue = this.leftLimit + parseInt((this.leftWidth - this.widthRem) / this.valueWidth * this.valueInterval); - if (this.roundUp) this.leftValue = parseInt(this.leftValue / this.roundUp) * this.roundUp; - this.rightValue = this.leftValue; - } - } -} \ No newline at end of file diff --git a/client/client/src/js/ui/UIManagerFlash.js b/client/client/src/js/ui/UIManagerFlash.js deleted file mode 100644 index b2d469c0..00000000 --- a/client/client/src/js/ui/UIManagerFlash.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - Copyright (c) 2013 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ -var UIManagerFlash = function () { - this.requestUnmute = function() { - trace("UIManagerFlash - requestUnmute"); - - $('#video_requestUnmuteDiv').removeClass().addClass('securityDiv'); - $('#closeButton_video_requestUnmuteDiv').css('visibility', 'hidden'); - $('#sendVideo').css('visibility', 'hidden'); - $('#requestUnmuteText').show(); - - $('#video').width(214); - $('#video').height(138); - getElement('video').style.top = "35px"; - - flashphoner.getAccessToAudioAndVideo(); - }; -} - -UIManagerFlash.prototype = { - requestUnmuteC2C: function() { - trace("UIManagerFlash - requestUnmuteC2C"); - $('.back').show(); - $('.request').show(); - $('#flash').removeClass('init').addClass('security'); - flashphoner.getAccessToAudioAndVideo(); - }, - - getAccessToAudioAndVideo: function() { - this.requestUnmute(); - }, - - getAccessToAudio: function() { - this.requestUnmute(); - }, - - getAccessToVideo: function() { - this.requestUnmute(); - }, - - - openVideoView: function() { - if (flashphoner.hasAccessToVideo()) { - flashphoner.viewVideo(); - $('#video_requestUnmuteDiv').removeClass().addClass('videoDiv'); - $('#closeButton_video_requestUnmuteDiv').css('visibility', 'visible'); - - $('#sendVideo').css('visibility', 'visible'); - $('#requestUnmuteText').hide(); - $('#video_requestUnmuteDiv .bar').html('  Video'); - - if (proportion != 0) { - var newHeight = $('.videoDiv').width() * proportion + 40; - $('.videoDiv').height(newHeight); //we resize video window for new proportion - } - $('#video_requestUnmuteDiv').resize(); - } else { - this.requestUnmute(); - if (intervalId == -1) { - intervalId = setInterval('if (flashphoner.hasAccessToVideo()){flashphoner_UI.closeRequestUnmute(); clearInterval(intervalId); intervalId = -1; flashphoner_UI.openVideoView();}', 500); - } - } - }, - - closeRequestUnmute: function() { - trace("UIManagerFlash - closeRequestUnmute"); - $('#video_requestUnmuteDiv').removeClass().addClass('closed'); - getElement('video').style.top = "20px"; - }, - - closeRequestUnmuteC2C: function() { - trace("UIManagerFlash - closeRequestUnmuteC2C"); - $('.back').hide(); - $('.request').hide(); - $('#flash').addClass('init').removeClass('security'); - } - }; \ No newline at end of file diff --git a/client/client/src/js/ui/UIManagerWebRtc.js b/client/client/src/js/ui/UIManagerWebRtc.js deleted file mode 100644 index 265a4c03..00000000 --- a/client/client/src/js/ui/UIManagerWebRtc.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - Copyright (c) 2013 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ -var UIManagerWebRtc = function () { - -} - -UIManagerWebRtc.prototype = { - requestUnmuteC2C: function() { - trace("UIManagerWebRTC - requestUnmute"); - openInfoView("Please allow access to media devices", 0, 60); - flashphoner.getAccessToAudio(); - }, - - getAccessToAudioAndVideo: function() { - trace("UIManagerWebRTC - getAccessToAudio"); - openInfoView("Please allow access to audio and video devices", 0, 60); - flashphoner.getAccessToAudioAndVideo(); - }, - - getAccessToAudio: function() { - trace("UIManagerWebRTC - getAccessToAudio"); - openInfoView("Please allow access to audio device", 0, 60); - flashphoner.getAccessToAudio(); - }, - - openVideoView: function() { - trace("UIManagerWebRTC - openVideoView"); - if (!flashphoner.hasAccessToVideo()){ - openInfoView("Please allow access to video device", 0, 60); - flashphoner.getAccessToAudioAndVideo(); - if (intervalId == -1) { - intervalId = setInterval('if (flashphoner.hasAccessToVideo()){flashphoner_UI.closeRequestUnmute(); clearInterval(intervalId); intervalId = -1; }', 500); - } - } - - $('#video_requestUnmuteDiv').removeClass().addClass('videoDiv'); - $('#closeButton_video_requestUnmuteDiv').css('visibility', 'visible'); - - $('#requestUnmuteText').hide(); - $('#video_requestUnmuteDiv .bar').html('  Video'); - - if (proportion != 0) { - var newHeight = $('.videoDiv').width() * proportion + 40; - $('.videoDiv').height(newHeight); //we resize video window for new proportion - } - $('#video_requestUnmuteDiv').resize(); - }, - - closeRequestUnmute: function() { - closeInfoView(); - }, - - closeRequestUnmuteC2C: function() { - this.closeRequestUnmute(); - } -}; \ No newline at end of file diff --git a/client/client/src/js/ws/Messenger.js b/client/client/src/js/ws/Messenger.js deleted file mode 100644 index c1c6f40b..00000000 --- a/client/client/src/js/ws/Messenger.js +++ /dev/null @@ -1,136 +0,0 @@ -/** - * Created with JetBrains WebStorm. - * User: Alex - * Date: 6/10/13 - * Time: 3:09 PM - * To change this template use File | Settings | File Templates. - */ -var Messenger = function (flashphoner) { - this.sentMessages = new Object(); -}; - -Messenger.prototype = { - - notifyMessage: function (message, notificationResult, sipObject) { - trace("Messenger - notifyMessage message: "+ message+" notificationResult: "+ notificationResult+" sipObject: "+ sipObject); - var sentMessage = this.sentMessages[message.id]; - if (sentMessage != null) { - sentMessage.state = message.state; - } - if (message.state == "SENT") { - this.notifySent(sentMessage); - } else if (message.state == "ACCEPTED") { - this.notifyAccepted(sentMessage); - } else if (message.state == "FAILED") { - this.notifyFailed(sentMessage); - } else if (message.state == "IMDN_DELIVERED") { - this.notifyDelivered(message, notificationResult); - } else if (message.state == "IMDN_FAILED" || message.state == "IMDN_FORBIDDEN" || message.state == "IMDN_ERROR") { - this.notifyDeliveryFailed(message.notificationResult); - } else if (message.state == "RECEIVED") { - //here we will choose what to display on multiple contacts in "from". - if (message.from.indexOf(",") != -1) { - var fromList = message.from.split(","); - message.from = fromList[0]; - } - //Don't show service message to user - if (message.contentType.toLowerCase() == "message/fsservice+xml") { - console.log("Received service message"); - } else { - this.notifyReceived(message, notificationResult); - } - } - }, - - notifyReceived: function (message, notificationResult) { - //received message - //send OK result on MESSAGE request - notifyMessageReceived(message); - this.sendOkResult(notificationResult); - }, - - notifyDeliveryFailed: function (sentMessage, notificationResult) { - if (sentMessage != null) { - //send OK result on IMDN request - notifyMessageDeliveryFailed(sentMessage); - this.removeSentMessage(sentMessage); - this.sendOkResult(notificationResult); - } - }, - - notifyDelivered: function (sentMessage, notificationResult) { - if (sentMessage != null) { - //send OK result on IMDN request - notifyMessageDelivered(sentMessage); - this.removeSentMessage(sentMessage); - this.sendOkResult(notificationResult); - } - }, - - notifyFailed: function (sentMessage) { - if (sentMessage != null) { - notifyMessageFailed(sentMessage); - this.removeSentMessage(sentMessage); - } - }, - - notifySent: function (sentMessage) { - if (sentMessage != null) { - notifyMessageSent(sentMessage); - } - }, - - notifyAccepted: function (sentMessage) { - if (sentMessage != null) { - notifyMessageAccepted(sentMessage); - if (!sentMessage.deliveryNotification) { - this.removeSentMessage(sentMessage); - } - } - }, - - removeSentMessage: function (sentMessage) { - setTimeout(function () { - messenger.sentMessages[sentMessage.id] = null; - }, 5000); - }, - - sendOkResult: function (notificationResult) { - notificationResult.status = "OK"; - this.sendResult(notificationResult); - }, - - sendResult: function (result) { - flashphoner.notificationResult(result); - }, - - sendMessage: function (message) { - this.saveSentMessage(message); - try { - flashphoner.sendMessage(message); - } catch (error) { - trace("Messenger - sending message error: "+error); - } - }, - - saveSentMessage: function (message) { - var id = this.createUUID(); - message.id = id; - this.sentMessages[id] = message; - }, - - createUUID: function () { - var s = []; - var hexDigits = "0123456789abcdef"; - for (var i = 0; i < 36; i++) { - s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); - } - s[14] = "4"; - s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); - s[8] = s[13] = s[18] = s[23] = "-"; - - var uuid = s.join(""); - - return uuid.substring(0, 18); - } -} \ No newline at end of file diff --git a/client/client/src/js/ws/SoundControl.js b/client/client/src/js/ws/SoundControl.js deleted file mode 100644 index 1b79cf3d..00000000 --- a/client/client/src/js/ws/SoundControl.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright (c) 2011 Flashphoner - All rights reserved. This Code and the accompanying materials - are made available under the terms of the GNU Public License v2.0 - which accompanies this distribution, and is available at - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Contributors: - Flashphoner - initial API and implementation - - This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. - */ -var SoundControl = function () { - me = this; - //Init sounds - me.registerSound = me.initSound(flashphonerLoader.registerSound, false, "auto"); - me.ringSound = me.initSound(flashphonerLoader.ringSound, true, "none"); - me.busySound = me.initSound(flashphonerLoader.busySound, false, "none"); - me.finishSound = me.initSound(flashphonerLoader.finishSound, false, "none"); -}; - -SoundControl.prototype = { - - //Creates HTML5 audio tag - initSound: function (src, loop, preload) { - if (typeof loop == 'undefined') { - loop = false; - } - var audioTag = document.createElement("audio"); - audioTag.autoplay = false; - audioTag.preload = preload; - if (loop) { - audioTag.loop = true; - } - //add src tag to audio tag - audioTag.src = src; - document.body.appendChild(audioTag); - return audioTag; - }, - - //plays audio - playSound: function (soundName) { - switch (soundName) { - case "RING": - if (!flashphonerLoader.disableLocalRing){ - me.ringSound.play(); - } - break - case "BUSY": - me.busySound.play(); - break - case "REGISTER": - me.registerSound.play(); - break - case "FINISH": - me.finishSound.play(); - break - default: - console.error("Do not know what to play on " + soundName); - - } - }, - - //stops audio - stopSound: function (soundName) { - trace("stopSound soundName: "+soundName+" me: "+me+" me.ringSound: "+me.ringSound); - switch (soundName) { - case "RING": - if (me.ringSound && !me.ringSound.paused) { - me.ringSound.pause(); - me.ringSound.currentTime = 0; - } - break; - default: - console.error("Do not know what to stop on " + soundName); - - } - } -}; \ No newline at end of file diff --git a/client/client/src/js/ws/WebSocketManager.js b/client/client/src/js/ws/WebSocketManager.js deleted file mode 100644 index 3f7e2d11..00000000 --- a/client/client/src/js/ws/WebSocketManager.js +++ /dev/null @@ -1,465 +0,0 @@ -var WebSocketManager = function (localVideoPreview, remoteVideo) { - var me = this; - me.calls = []; - me.isOpened = false; - me.configLoaded = false; - me.webRtcMediaManager = new WebRtcMediaManager(localVideoPreview, remoteVideo); - me.soundControl = new SoundControl(); - me.stripCodecs = new Array(); - - var rtcManager = this.webRtcMediaManager; - var proccessCall = function (call) { - for (var i in me.calls) { - if (call.id == me.calls[i].id) { - me.calls[i] = call; - return; - } - } - me.calls.push(call); - notifyAddCall(call); - }; - - var getCall = function (callId) { - for (var i in me.calls) { - if (callId == me.calls[i].id) { - return me.calls[i]; - } - } - }; - - var removeCall = function (callId) { - for (var i in me.calls) { - if (callId == me.calls[i].id) { - me.calls.splice(i, 1); - } - } - if (me.calls.length == 0) { - rtcManager.close(); - } - }; - - this.callbacks = { - ping: function () { - me.webSocket.send("pong"); - }, - - getUserData: function (user) { - me.user = user; - notifyRegisterRequired(user.regRequired); - notifyConnected(); - }, - - getVersion: function (version) { - notifyVersion(version); - }, - - registered: function (sipHeader) { - notifyRegistered(sipHeader); - }, - - ring: function (call, sipHeader) { - trace("ring call.state: "+call.state+" call.id: "+call.id ) - proccessCall(call); - notify(call); - }, - - sessionProgress: function (call, sipHeader) { - trace("sessionProgress call.state: "+call.state+" call.id: "+call.id ) - proccessCall(call); - notify(call); - }, - - setRemoteSDP: function (call, sdp, isInitiator, sipHeader) { - proccessCall(call); - this.stopSound("RING"); - rtcManager.setRemoteSDP(sdp, isInitiator); - if (!isInitiator && rtcManager.getConnectionState() == "established") { - me.answer(call.id); - } - }, - - talk: function (call, sipHeader) { - proccessCall(call); - notify(call); - }, - - hold: function (call, sipHeader) { - proccessCall(call); - notify(call); - }, - - callbackHold: function (callId, isHold) { - var call = getCall(callId); - notifyCallbackHold(call, isHold); - }, - - finish: function (call, sipHeader) { - proccessCall(call); - notify(call); - notifyRemoveCall(call); - removeCall(call.id); - }, - - busy: function (call, sipHeader) { - proccessCall(call); - notify(call); - }, - - fail: function (errorCode, sipHeader) { - notifyError(errorCode); - }, - - notifyVideoFormat: function (videoFormat) { - //notifyVideoFormat(videoFormat); - }, - - notifyBugReport: function (filename) { - notifyBugReport(filename); - }, - - notifyMessage: function (message, notificationResult, sipObject) { - messenger.notifyMessage(message, notificationResult, sipObject); - }, - - notifyAudioCodec: function (codec) { - }, - - notifySubscription: function (subscriptionObject, sipObject) { - notifySubscription(subscriptionObject, sipObject); - }, - - notifyXcapResponse: function (xcapResponse) { - notifyXcapResponse(xcapResponse); - } - }; - - -}; - -WebSocketManager.prototype = { - - login: function (loginObject, WCSUrl) { - var me = this; - me.webSocket = $.websocket(WCSUrl, { - open: function () { - me.isOpened = true; - me.webSocket.send("connect", loginObject); - }, - close: function (event) { - me.isOpened = false; - if (!event.originalEvent.wasClean) { - notifyError(CONNECTION_ERROR); - } - notifyCloseConnection(); - me.webRtcMediaManager.close(); - }, - error: function () { - }, - context: me, - events: me.callbacks - }); - return 0; - }, - - loginByToken: function (WCSUrl, token, pageUrl) { - var me = this; - var obj = {}; - obj.token = token; - obj.pageUrl = pageUrl; - - me.login(obj, WCSUrl); - return 0; - }, - - callByToken: function (callRequest) { - var me = this; - openInfoView("Configuring WebRTC connection...", 0); - this.webRtcMediaManager.createOffer(function (sdp) { - closeInfoView(); - callRequest.sdp = sdp; - me.webSocket.send("call", callRequest); - }, false); - return 0; - - }, - - logoff: function () { - trace("WebSocketManager - logoff"); - this.webSocket.close(); - }, - - subscribe: function (subscribeObject) { - this.webSocket.send("subscribe", subscribeObject); - }, - - sendXcapRequest: function (xcapUrl) { - this.webSocket.send("sendXcapRequest", xcapUrl); - }, - - call: function (callRequest) { - var me = this; - openInfoView("Configuring WebRTC connection...", 0, 60); - this.webRtcMediaManager.createOffer(function (sdp) { - closeInfoView(); - //here we will strip codecs from SDP if requested - if (me.stripCodecs.length) { - sdp = me.stripCodecsSDP(sdp); - console.log("New SDP: " + sdp); - } - sdp = me.removeCandidatesFromSDP(sdp); - callRequest.sdp = sdp; - me.webSocket.send("call", callRequest); - }, callRequest.hasVideo); - return 0; - }, - - msrpCall: function (callRequest) { - var me = this; - me.webSocket.send("msrpCall", callRequest); - return 0; - }, - - setSendVideo: function (callId, hasVideo) { -// var me = this; -// this.webRtcMediaManager.createOffer(function (sdp) { -// me.webSocket.send("changeMediaRequest", {callId: callId, sdp: sdp}); -// }, hasVideo); -// return 0; - }, - - answer: function (callId, hasVideo) { - var me = this; - openInfoView("Configuring WebRTC connection...", 0, 60); - /** - * If we receive INVITE without SDP, we should send answer with SDP based on webRtcMediaManager.createOffer because we do not have remoteSdp here - */ - if (this.webRtcMediaManager.lastReceivedSdp !== null && this.webRtcMediaManager.lastReceivedSdp.length == 0) { - this.webRtcMediaManager.createOffer(function (sdp) { - closeInfoView(); - //here we will strip codecs from SDP if requested - if (me.stripCodecs.length) { - sdp = me.stripCodecsSDP(sdp); - console.log("New SDP: " + sdp); - } - sdp = me.removeCandidatesFromSDP(sdp); - me.webSocket.send("answer", {callId: callId, hasVideo: hasVideo, sdp: sdp}); - }, hasVideo); - } else { - /** - * If we receive a normal INVITE with SDP we should create answering SDP using normal createAnswer method because we already have remoteSdp here. - */ - this.webRtcMediaManager.createAnswer(function (sdp) { - closeInfoView(); - me.webSocket.send("answer", {callId: callId, hasVideo: hasVideo, sdp: sdp}); - }, hasVideo); - } - }, - - hangup: function (callId) { - if (callId) { - this.webSocket.send("hangup", callId); - } else { - if (this.calls.length == 0) { - closeInfoView(); - toCallState(); - this.webRtcMediaManager.close(); - } - } - }, - - setStatusHold: function (callId, isHold) { - this.webSocket.send("hold", {callId: callId, isHold: isHold}); - }, - - transfer: function (callId, callee) { - this.webSocket.send("transfer", {callId: callId, callee: callee}); - }, - - sendDTMF: function (callId, dtmf) { - this.webSocket.send("sendDtmf", {callId: callId, dtmf: dtmf}); - }, - - setUseProxy: function (useProxy) { - if (this.isOpened) { - this.webSocket.send("setUseProxy", useProxy); - } - }, - - pushLogs: function (logs) { - if (this.isOpened) { - this.webSocket.send("pushLogs", logs) - return true; - } else { - return false; - } - }, - - submitBugReport: function (reportObject) { - if (this.isOpened) { - this.webSocket.send("submitBugReport", reportObject) - return true; - } else { - return false; - } - }, - - setLTState: function (state) { - trace("setLTState: " + state); - this.webSocket.send("setLTState", {state: state}); - }, - - getAccessToAudioAndVideo: function () { - this.webRtcMediaManager.getAccessToAudioAndVideo(); - }, - - getAccessToAudio: function () { - this.webRtcMediaManager.getAccessToAudio(); - }, - - getVolume: function () { - return this.webRtcMediaManager.remoteVideo.volume * 100; - }, - - setVolume: function (value) { - this.webRtcMediaManager.remoteVideo.volume = value / 100; - }, - - hasAccessToAudio: function () { - return this.webRtcMediaManager.isAudioMuted == -1; - }, - - hasAccessToVideo: function () { - return this.webRtcMediaManager.isVideoMuted == -1; - }, - - getInfoAboutMe: function () { - return this.user; - }, - - getCookie: function (c_name) { - var i, x, y, ARRcookies = document.cookie.split(";"); - for (i = 0; i < ARRcookies.length; i++) { - x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("=")); - x = x.replace(/^\s+|\s+$/g, ""); - if (x == c_name) { - return ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1); - } - } - }, - - setCookie: function (c_name, value) { - var exdate = new Date(); - exdate.setDate(exdate.getDate() + 100); - var c_value = escape(value) + "; expires=" + exdate.toUTCString(); - document.cookie = c_name + "=" + c_value; - }, - - playSound: function (sound) { - this.soundControl.playSound(sound); - }, - - stopSound: function (sound) { - this.soundControl.stopSound(sound); - }, - - sendMessage: function (message) { - this.webSocket.send("sendInstantMessage", message); - }, - - notificationResult: function (result) { - this.webSocket.send("notificationResult", result); - }, - - setStripCodecs: function (array) { - this.stripCodecs = array; - }, - - removeCandidatesFromSDP: function (sdp) { - var sdpArray = sdp.split("\n"); - - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i].search("a=candidate:") != -1) { - sdpArray[i] = ""; - } - } - - //normalize sdp after modifications - var result = ""; - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i] != "") { - result += sdpArray[i] + "\n"; - } - } - - return result; - }, - - stripCodecsSDP: function (sdp) { - var sdpArray = sdp.split("\n"); - console.dir(this.stripCodecs); - - //search and delete codecs line - var pt = []; - for (p = 0; p < this.stripCodecs.length; p++) { - console.log("Searching for codec " + this.stripCodecs[p]); - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i].search(this.stripCodecs[p]) != -1 && sdpArray[i].indexOf("a=rtpmap") == 0) { - console.log(this.stripCodecs[p] + " detected"); - pt.push(sdpArray[i].match(/[0-9]+/)[0]); - sdpArray[i] = ""; - } - } - } - - if (pt.length) { - //searching for fmtp - for (p = 0; p < pt.length; p++) { - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i].search("a=fmtp:" + pt[p]) != -1) { - console.log("PT " + pt[p] + " detected"); - sdpArray[i] = ""; - } - if (sdpArray[i].search("a=candidate:") != -1) { - sdpArray[i] = ""; - } - } - } - - //delete entries from m= line - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i].search("m=audio") != -1) { - console.log("m line detected " + sdpArray[i]); - var mLineSplitted = sdpArray[i].split(" "); - var newMLine = ""; - for (m = 0; m < mLineSplitted.length; m++) { - if (pt.indexOf(mLineSplitted[m]) == -1 || m <= 2) { - newMLine += mLineSplitted[m]; - if ( m < mLineSplitted.length-1 ){ - newMLine = newMLine + " "; - } - } - } - sdpArray[i]=newMLine; - console.log("Resulting m= line is: " + sdpArray[i]); - break; - } - } - } - - //normalize sdp after modifications - var result = ""; - for (i = 0; i < sdpArray.length; i++) { - if (sdpArray[i] != "") { - result += sdpArray[i] + "\n"; - } - } - - return result; - }, - - setStunServer: function (server) { - this.webRtcMediaManager.setStunServer(server); - } - -}; - diff --git a/client/client/src/phone.mxml b/client/client/src/phone.mxml deleted file mode 100644 index d487016e..00000000 --- a/client/client/src/phone.mxml +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - 0){ - DataPhone.getInstance().viewController.showConnectingView(); - DataPhone.getInstance().flash_API.loginByToken(token); - }else{ - DataPhone.getInstance().viewController.hideConnectingView(); - } - } - } - - private function checkState(event:TimerEvent = null):void{ - if (flash_API.isInitialized()){ - Logger.info("FlashAPI has been initialized"); - flash_API.initMedia(); - dropTimer(); - } - } - - private function onOpenInstantMessageChatView():void{ - if (!flash_API.modelLocator.logged){ - phone(Application.application).onOpenSipAccountView(); - return; - } - var callee:String = mainView.callee.text; - if (((callee != null) && (callee.length > 0)) || (DataPhone.getInstance().tabChatView.size() > 0)){ - PopUpManager.addPopUp(DataPhone.getInstance().tabChatView,this); - PopUpManager.centerPopUp(DataPhone.getInstance().tabChatView); - if ((callee != null) && (callee.length > 0)){ - DataPhone.getInstance().tabChatView.addTab(callee); - } - }else{ - infoView.text = "Enter callee"; - PopUpManager.addPopUp(infoView,DisplayObject(Application.application),true); - PopUpManager.centerPopUp(infoView); - } - } - - private function onOpenMicrophoneSettingsView():void{ - flash_API.soundControl.getMicrophone().setLoopBack(true); - PopUpManager.addPopUp(DataPhone.getInstance().microphoneSettingsView,this); - PopUpManager.centerPopUp(DataPhone.getInstance().microphoneSettingsView); - } - public function onOpenSipAccountView():void{ - if (loginButton.text == "Log in"){ - var token:String; - try{ - if (Application.application.parameters != null && Application.application.parameters.token!=null){ - token = Application.application.parameters.token; - } - } catch (e:Error){ - token = ""; - } - if (token != null && token.length > 0){ - DataPhone.getInstance().viewController.showConnectingView(); - DataPhone.getInstance().flash_API.loginByToken(token); - }else{ - PopUpManager.addPopUp(DataPhone.getInstance().sipAccountView,this); - PopUpManager.centerPopUp(DataPhone.getInstance().sipAccountView); - } - }else{ - logout(); - } - } - public function toLoggedState():void{ - loginButton.text="Log out"; - } - - public function toLoggedOffState():void{ - loginButton.text="Log in"; - } - private function logout():void{ - DataPhone.getInstance().flash_API.logoff(); - toLoggedOffState(); - } - - public function onOpenVideoView():void{ - videoView.init(); - } - - ]]> - - - - - - - - - - - - - - - diff --git a/client/client/src/sounds/BUSY.ogg b/client/client/src/sounds/BUSY.ogg deleted file mode 100644 index 8f3dd050..00000000 Binary files a/client/client/src/sounds/BUSY.ogg and /dev/null differ diff --git a/client/client/src/sounds/CALL_IN.ogg b/client/client/src/sounds/CALL_IN.ogg deleted file mode 100644 index a343524e..00000000 Binary files a/client/client/src/sounds/CALL_IN.ogg and /dev/null differ diff --git a/client/client/src/sounds/CALL_OUT.ogg b/client/client/src/sounds/CALL_OUT.ogg deleted file mode 100644 index da21787d..00000000 Binary files a/client/client/src/sounds/CALL_OUT.ogg and /dev/null differ diff --git a/client/client/src/sounds/HANGUP.ogg b/client/client/src/sounds/HANGUP.ogg deleted file mode 100644 index 7adcd9fd..00000000 Binary files a/client/client/src/sounds/HANGUP.ogg and /dev/null differ diff --git a/client/client/src/sounds/REGISTER.ogg b/client/client/src/sounds/REGISTER.ogg deleted file mode 100644 index 912f9bc7..00000000 Binary files a/client/client/src/sounds/REGISTER.ogg and /dev/null differ diff --git a/client/client/src/styles/arial.ttf b/client/client/src/styles/arial.ttf deleted file mode 100644 index 3d6805df..00000000 Binary files a/client/client/src/styles/arial.ttf and /dev/null differ diff --git a/client/client/src/styles/style.css b/client/client/src/styles/style.css deleted file mode 100644 index 4e3f4090..00000000 --- a/client/client/src/styles/style.css +++ /dev/null @@ -1,171 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -ToolTip -{ - cornerRadius: 0; - fontSize: 11; - fontFamily: Arial; - paddingRight: 3; - paddingLeft: 4; - color: #404040; - fontWeight: normal; -} -TextInput -{ - backgroundColor: #DEEEFF; - borderStyle: solid; - fontFamily: Arial; - borderThickness: 1; - cornerRadius: 3; - paddingTop: 2; -} - - -Label.boldText -{ - fontWeight: bold; - fontSize: 11; - fontFamily: Verdana; -} -Button -{ - fontSize: 12; - fontFamily: Arial; - fontWeight: normal; - leading: 2; - cornerRadius: 3; - fillAlphas: 1.0, 1.0; - fillColors: #DCDCDC, #DCDCDC, #EEEEEE, #EEEEEE; - borderColor: #B7BABC; - themeColor: #B7BABC; - color: #000000; - textRollOverColor: #000000; - textSelectedColor: #000000; - paddingLeft: 0; - paddingRight: 0; - -} - - -Button.close -{ - borderColor: #FF0000; - color: #000; - cornerRadius: 10; - fillColors: #FF0000, #FF0000, #FF0000, #FF0000; - fontSize: 10; - fontStyle: normal; - themeColor: #FF0000; - paddingBottom: 3; - paddingLeft: 3; - paddingRight: 3; - paddingTop: 3; - fontWeight: bold; -} - - - -Label.callState -{ - fontWeight: bold; - color: #FF0000; - fontSize: 12; - fontFamily: Verdana; -} - -CallView{ - color:green; -} - -Label.error -{ - fontWeight: bold; - color: #FF0000; - fontSize: 12; - fontFamily: Verdana; -} - -Label.VideoMessage -{ - fontWeight: bold; - color: #FF0000; - fontSize: 16; - fontFamily: Verdana; - text-align:right; -} - - -Application -{ - backgroundGradientAlphas: 1.0, 1.0; - backgroundGradientColors: #FFFFFF, #FFFFFF; - fontFamily: Verdana; - theme-color:#ffffff; - color: #000000; -} -ApplicationControlBar -{ - fillAlphas: 1.0, 1.0; - fillColors: #000000, #000000; -} -LinkButton.AppBarButton -{ - color: #FFFFFF; - textRollOverColor: #FFFFFF; - textSelectedColor: #FFFFFF; - rollOverColor: #A0A0A0; - selectionColor: #A0A0A0; -} -Panel -{ - backgroundColor: #FFFFFF; - borderColor: #A5CCFF; - borderAlpha: 1.0; - titleStyleName: panelTitle; - borderThicknessLeft: 0; - borderThicknessRight: 0; - fontFamily: Arial; - fontSize: 12; - borderThicknessTop: 0; - borderThicknessBottom: 0; - statusStyleName: panelStatus; - controlBarStyleName: panelControlBar; - headerHeight: 0; - cornerRadius: 3; - dropShadowColor: #000000; - dropShadowEnabled: false; -} -Panel.Login -{ - padding-bottom:3; - padding-left:3; - padding-right:3; - padding-top:3; - cornerRadius: 0; - roundedBottomCorners: false; -} - -@font-face { - font-family: Verdana; - fontWeight: normal; - fontStyle: normal; - src: url("verdana.ttf"); -} - -@font-face { - font-family: Arial; - fontWeight: normal; - fontStyle: normal; - src: url("arial.ttf"); -} - diff --git a/client/client/src/styles/style_html.css b/client/client/src/styles/style_html.css deleted file mode 100644 index 26ac907a..00000000 --- a/client/client/src/styles/style_html.css +++ /dev/null @@ -1,961 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and -MPL license for Flashphoner buyers. Other license versions by negatiation. -Write us support@flashphoner.com with any questions. -*/ - -body { - font: 12px Arial; -} -img { - border: 0; -} -button::-moz-focus-inner, -input[type="reset"]::-moz-focus-inner, -input[type="button"]::-moz-focus-inner, -input[type="submit"]::-moz-focus-inner, -input[type="file"] > input[type="button"]::-moz-focus-inner { - border: none; -} - -/* -------- Backgrounds ------- */ -#settingsView, #loginDiv, #infoDiv, #connectingDiv, .login_link, #transfer, #incomingDiv, #newChat { - background: #fff; -} -#controlPanel, .bar, .videoDiv, #chatDiv, #tabul, .button { - background-color: #ddd; -} - -/* ---------- Positions --------- */ -#video, -#phoneDiv, -#loginDiv, -#incomingDiv, -#infoDiv, -#connectingDiv, -#settingsView, -#versionOfProduct, -#controlPanel, -.closeButton, -.transferButton, -.holdButton, -.holdImage, -.bar, -#settingsButtonInCallView, -#answerButton, -#hangupButton, -#callerLogin, -#logoutButton, -#loginMainButton, -#video_requestUnmuteDiv, -#sendVideo, -#requestUnmuteText, -#closeButton_video_requestUnmuteDiv, -#transfer, -.callDiv, -.caller, -#chatDiv, -#micSlider, #speakerSlider, -#micBack, #speakerBack, -#console { - position: absolute; -} -/* ---------- Border ------------ */ -#settingsView, #loginDiv, #infoDiv, #connectingDiv, #transfer, #incomingDiv, #video_requestUnmuteDiv, #controlPanel, #chatDiv { - border-width: 2px 5px 5px\0/; /*only for ie8*/ - border-style: solid\0/; /*only for ie8*/ - border-color: #ddd\0/; /*only for ie8*/ - border: 1px solid #aaa; -} -#connectingDiv, #infoDiv { - border-width: 5px\0/; /*only for ie8*/ -} -/* ---------- Shadow ----------*/ -#settingsView, #transfer, #infoDiv, #loginDiv, #connectingDiv, #video_requestUnmuteDiv, #incomingDiv, #chatDiv -{ - box-shadow: 0 0 10px rgba(0,0,0,0.35); - -moz-box-shadow: 0 0 10px rgba(0,0,0,0.35); - -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.35); -} - -/* ----------------------------- */ -textarea, text, input { - outline: none; - -moz-appearance: none; -} -input::-webkit-input-placeholder { - color: #ccc; - font: 14px Arial; -} -#calleeText { - padding-left: 1px; -} -#phoneDiv { - left: 30px; - height: 240px; - width: 153px; - padding: 10px; - position: relative; - top: 21px; -} -#versionOfProduct { - top: 134px; - right: 17px; - font: 8px Arial; - color: #bbb; -} -#controlPanel { - width: 152px; - height: 20px; - top: 6px; - left: 10px; - border: 1px solid #bbb; - box-shadow: /*0px 1px 0px #fff, */inset 0px 1px 0px #fff; -} - -/* ---------------- Buttons ---------------- */ -.closeButton { - background: url(../assets/close.png); - right: 3px; - opacity: 0.7; - top: 3px; - width: 14px; - height: 14px; -} -#cameraButton { - background: url(../assets/camera.png) no-repeat center; -} -#micButton { - background: url(../assets/mic.png) no-repeat center; -} -#soundButton { - background: url(../assets/speaker.png) no-repeat center; -} -.iconButton { - width: 24px; - height: 20px; - float: left; - cursor: pointer; - /* - -moz-opacity: 0.6; - -khtml-opacity: 0.6; - opacity: 0.6; - */ -} - -.iconBackgroundPressed{ - width: 24px; - height: 20px; - /*background: -webkit-radial-gradient(#aaa, #ddd, #eee, #eee);*/ - float: left; -} - -.iconPressed{ -} - -.iconButton:hover { - -moz-opacity: 1; - -khtml-opacity: 1; - opacity: 1; -} -.transferButton, .holdButton { - top: 97px; - width: 14px; - height: 14px; -} -.closeButton { - background: url(../assets/close.png); - right: 3px; -} -.transferButton { - background: url(../assets/transfer.png); - right: 7px; -} -.holdButton { - background: url(../assets/hold.png); - right: 27px; - visibility:hidden; -} - -.holdImage { - background: url(../assets/hold_big.png); - right: 55px; - top: 57px; - width: 30px; - height: 30px; - visibility: hidden; -} -/* ----------------------------------------- */ -/* ------------- ��������� �������� ------------ */ -.bar { - top: 0; - left: 0; - width: 100%; - height: 20px; - cursor: move; - font: 12px Arial; - font-weight: bolder; - color: #999; - text-shadow: #fff 0px 1px; - line-height: 20px; - text-align: left; - box-shadow: inset 0 1px 0 #fff; -} -/* ----------------------------------- */ -/* ------------- Settings ------------ -#settingsDiv { - top: 80px; - left: 5px; - height: 113px; - width: 230px; - padding-top: 20px; - visibility: hidden; - background: url(../assets/mic_settings_background.png); -} -#settingsButton { - top: 2px; - left: 5px; - background: url(../assets/mic_settings.png); -} -#settingsButtonInCallView { - top: 98px; - left: 5px; - background: url(../assets/mic_settings.png); -} --------------------------------------- */ - -/* ------------- Settings ------------ */ - -#settingsView, #settingsOkButton, #micSelector, #camSelector, -#settingsMicImage, #settingsCamImage { - position: absolute; -} - -#settingsView { - top: 94px; - left: 8px; - height: 123px; - width: 230px; - padding-top: 20px; - display: none; -} -#settingsButton { - background: url(../assets/mic_settings_2.png) no-repeat center; - /*top: 19px; - left: 18px; - /*width: 140px;*/ - opacity: 0.65; -} -#settingsOkButton{ - top: 100px; - left: 72px; - width: 80px; -} -#micSelector{ - top: 32px; - left: 45px; - width: 170px; -} -#camSelector{ - top: 64px; - left: 45px; - width: 170px; -} -#settingsMicImage{ - top: 35px; - left: 14px; -} - -#settingsCamImage{ - top: 67px; - left: 15px; -} -/* -------------------------------------- */ - -/* ----------------- Incoming call view ---------------- */ -#incomingDiv { - top: 110px; - left: 5px; - height: 82px; - width: 215px; - border: 1px solid #bbb; - padding: 5px; - padding-top: 25px; - font: 16px Arial; - text-align: center; - color: #aaa; - display: none; -} -#answerButton, #hangupButton { - width: 80px; - /*height: 22px;*/ - /*color: white;*/ - top: 70px; -} -#answerButton { - background-color: #009900; - left: 28px; -} -#hangupButton { - background-color: #cc0000; - right: 27px; -} -#callerField { - font-weight: bold; - color: #000; -} -/* ------------------ Connecting ------------------------ */ -#connectingDiv { - top: 120px; - left: 10px; - height: 40px; - width: 200px; - padding: 10px; - float: left; - visibility: hidden; - font: 16px Arial; - color: #aaa; - text-align: center; - display: table; -} -#connectingText { - display: table-cell; - vertical-align: middle; -} -/* ------------------ Info ------------------------ */ -#infoDiv { - top: 120px; - left: 10px; - height: 30px; - width: 200px; - padding: 10px; - float: left; - visibility: hidden; - font: 16px Arial; - color: #aaa; - text-align: center; - line-height: 30px; - -moz-opacity: 0.95; - /* Mozilla 1.6 */ - -khtml-opacity: 0.95; - /* Konqueror 3.1, Safari 1.1 */ - opacity: 0.95; - /* CSS3 - Mozilla 1.7b +, Firefox 0.9 +, Safari 1.2+, Opera 9+ */ -} -#infoText { -} -/* --------- Login, logout --------------------------------------------- */ -#callerLogin { - top: 0px; - right: 0px; - font: 12px Arial; - width: 50px; - height: 20px; - float: left; - text-align: right; - overflow: hidden; - color: #333; - display: none; - font: bold 12px Helvetica; - text-shadow: 0 1px 0 #fff; - line-height: 20px; - padding-right: 5px; - cursor: pointer; -} -#logoutButton { - width: 60px; - height: 20px; - bottom: -22px; - right: 0px; - font-size: 12px; - line-height: 20px; - display: none; -} -#loginDiv { - top: 46px; - left: 10px; - height: 172px; - width: 200px; - padding: 20px; - padding-top: 25px; - float: left; - visibility: hidden; -} -#loginMainButton { - top: -1px; - right: -1px; - font-size: 12px; - border: 1px solid #aaa; - padding: 0 5px 0 5px; - margin: 0px; - width:40px; - height: 20px; - line-height: 20px; - text-shadow: 0 1px 0 #eee; - -} - -#loginButton { - margin: 10px 0 0 15px; - width: 80px; -} - -#bugReportText { - position: absolute; - top: 360px; - left: 250px; - height: 50px; - width: 500px; - float: left; - font: 14px Courier; - color: #ffffff; - padding: 1px; - visibility: visible; - text-align: left; - border: 1px solid #aaa; - background-color: #333; -} - -#bugReportButton { - position: absolute; - top: 370px; - left: 760px; - width: 200px; - height: 50px; - font: 14px Courier; - padding: 1px; - visibility: visible; - text-align: center; - text-decoration: underline; - color: #333; - text-shadow: 0px 1px 0 #fff; - box-shadow: /*0px 1px 0px #fff*/ inset 0px 1px 0px #fff; - border-radius: 0px; - cursor: pointer; - border: #333333; -} - -#testButton { - position: absolute; - top: 330px; - left: 250px; - height: 20px; - width: 80px; - float: left; - background-color: green; - font: 14px Courier; - color: #ffffff; - padding: 1px; - visibility: hidden; - text-align: center; -} - -/* ------------ Video + Security settings view -------------- */ -#video_requestUnmuteDiv { - top: 32px; - left: 238px; - overflow: hidden; - padding-top: 20px; - -} -.videoDiv { - visibility: visible; - width: 640px; - height: 520px; -} -.securityDiv { - visibility: visible; - width: 215px; - height: 178px; - background-color: #fff; - padding-top: 20px; - border: 1px solid #ccc; -} -.closed { - width: 1px !important; - height: 1px !important; - visibility: hidden; -} -/* -we use '.init' class to make div size 1x1 basically -Because Firefox can`t operate with swf object located in -div with zero size. -*/ -.init { - width: 1px; - height: 1px; - visibility: hidden; -} - -#sendVideo { - width: 100px; - bottom: 6px; - left: 6px; -} -#requestUnmuteText { - text-align: center; - width: 100%; - font-weight: bolder; -} -#closeButton_video_requestUnmuteDiv{ - background: url(../assets/close.png); - right: 3px; - opacity: 0.7; - top: 3px; - width: 14px; - height: 14px; -} -/* -------------------------------------- */ -/* ------------ Transfer view -------------- */ -#transfer { - width: 200px; - height: 94px; - top: 90px; - left: 20px; - text-align: center; - font: bold 16px Arial; - padding: 10px; - padding-top: 30px; - visibility: hidden; -} -#transferInput { - width: 180px; - margin-bottom: 20px; -} -#transferOk, #transferCansel { - width: 80px; - margin: 0 6px 0 16px; -} -#transferCansel { - margin: 0; -} - -/* -------------------------------------- */ -/* ------ Call view-------- */ -.callDiv { - width: 152px; - height: 118px; - top: 57px; - left: 49px; - float: left; - background: #333; - /*border: 1px solid #B7BABC;*/ - color: #eee; - font: 22px Arial; - visibility: hidden; -} -.caller { - float: left; - top: 35px; - text-align: center; - width: 100%; -} -#callState { - color: #ddd; - position: relative; - top: 64px; - font-size: 12px; - text-align: center; -} -/* ------------------------- */ -/* ------ Chat view -------- */ -#chatDiv { - width: 320px; - top: 250px; - left: 20px; - visibility: hidden; -} -.chatBox { - width: 100%; - height: 100%; - margin: 0; - border: 1px solid #ddd; - background: #fff; -} -.chatTextarea { - border: 0; - width: 305px; - height: 200px; - margin: 5px; - resize: none; - overflow: auto; - word-wrap: break-word; -} -.messageInput { - margin: 4px; - width: 238px; - float: left; -} -.messageSend { - margin-top: 3px; - width: 60px; - margin-right: 3px; -} -.myNick, .yourNick { - color: #ccc; - font-weight: bold; - padding-top: 7px; -} -.yourNick { - color: #91c8ff; -} - -.message_sent { - color: gray; -} - -.message_accepted { - color: green; -} - -.message_failed { - color: red; -} - -.message_delivery_failed{ - color:orange; -} - -.message_delivered { - color: black; -} - -#tabul { - padding: 0; - margin: 0; - margin-left: 50px; - padding: 0; - z-index: 10; -} -#tabul li { - display: inline; - cursor: pointer; - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; -} -.ntabs { - background: #ddd; - margin-right: -1px; - font-size: 11px; - font-weight: bold; - color: #333; - padding: 4px 2px 2px 6px; - position: relative; - max-width: 200px; - text-overflow: ellipsis; -} -.add { - padding: 3px 5px; -} -.ctab { - background: #fff; - position: relative; - border-bottom-color: #fff; -} -.close { - text-decoration: none; - color: #bbb; - font-size: 16px; - padding: 0 4px; -} -.close:hover { - color: #333; -} -#tabcontent { - z-index: -10; - position: relative; - top: -1px; - border-top: none; - height: 240px; -} -/* ---------------------------------------------------- */ - -.button { - /*background: #dcdcdc;*/ - width: 50px; - height: 28px; - float: left; - margin: 0px -1px 0px 0; - text-align: center; - -moz-user-select: none; - -khtml-user-select: none; - user-select: none; - font: bold 14px Helvetica; - border: 1px solid #aaa; - color: #333; - text-shadow: 0px 1px 0 #fff; - box-shadow: /*0px 1px 0px #fff*/ inset 0px 1px 0px #fff; - text-align: center; - border-radius: 0px; - cursor: pointer; - /* - background: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#ddd)); - background: -moz-linear-gradient(top, #ddd, #ccc); - background: -o-linear-gradient(top, #ddd, #ccc); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#dddddd', endColorstr='#cccccc'); - */ - line-height: 28px; - font-family: ; -} - -.buttonLine { - float: left; - height: 29px; -} - -.chat, .call, .hangup { - width: 75px; - color: #000; - -} -.chat { - box-shadow: 0px 1px 0px #fff, inset 0px 1px 0px #C2DDF2; /*#A8CFEC;/* #96C6E9;*/ - text-shadow: 0px 1px 0 #A8CFEC; - background: -webkit-gradient(linear, left top, left bottom, from(#A1CCEB), to(#7BB8E4)); - /*background: -webkit-gradient(linear, left top, left bottom, from(#7CB8E3), to(#419AD9));*/ - background: -moz-linear-gradient(top, #ddd, #ccc); - background: -o-linear-gradient(top, #ddd, #ccc); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#dddddd', endColorstr='#cccccc'); - /*color: #1B527A;*/ - width: 76px; -} -.call { - box-shadow: 0px 1px 0px #fff, inset 0px 1px 0px #4DE74D;/*#0d0;*/ - text-shadow: 0px 1px 0px #0d0; - background: -webkit-gradient(linear, left top, left bottom, from(#6ECF6E), to(#4DC34D)); - /*background: -webkit-gradient(linear, left top, left bottom, from(#3b3), to(#0a0));*/ - background: -moz-linear-gradient(top, #3b3, #0a0); - background: -o-linear-gradient(top, #3b3, #0a0); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#33bb33', endColorstr='#00aa00'); - /*color: #004400;*/ - border-left-color: #888; - -} -.hangup { - box-shadow: 0px 1px 0px #fff, inset 0px 1px 0px #FF9494;/*#f66;*/ - text-shadow: 0px 1px 0 #f33; - background: -webkit-gradient(linear, left top, left bottom, from(#E16C6C), to(#DB4D4D)); - /*background: -webkit-gradient(linear, left top, left bottom, from(#f33), to(#c00));*/ - background: -moz-linear-gradient(top, #f33, #c00); - background: -o-linear-gradient(top, #f33, #c00); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#ff3333', endColorstr='#cc0000'); -} - -.pressed { - border-color: #888; - /*border-bottom-color: #fff;*/ - box-shadow: inset 0px 1px 6px #333; - /*height: 23px;*/ - line-height: 30px; - /*border-radius: 4px 4px 5px 5px;*/ - background-color: #d7d7d7; -} - -.disabled { - opacity: 0.7; -} - -.call_button, .chat_button { - width: 81px; - background-color: #009800; - float: left; - height: 30px; - font: 20px Arial; - color: #fff; - text-align: center; - line-height: 30px; - border: 1px outset; - -moz-user-select: none; - -khtml-user-select: none; - user-select: none; - cursor: default; - margin-bottom: 3px; -} - - - -/* ----------- Slider -------------- */ -#micSlider, #speakerSlider { - top: 10px; - display: none; -} -#micBack, #speakerBack { - /* TODO replace sliders within sliderbackground*/ - top: 20px; - width: 24px; - height: 102px; - background: #ddd; - box-shadow: 0px 0px 4px #bbb; - display: none; - border: 1px solid #aaa; - border-top: none; -} -#micBack { - left: 23px; -} -#speakerBack { - left: -1px; -} -#micSlider { - left: 8px; -} -#speakerSlider { - left: 8px; -} -.ui-slider-vertical { - width: 6px !important; - height: 80px !important; - border: 1px solid #999 !important; - background-color: #ddd !important; - box-shadow: inset 0px 0px 1px #777 !important; - } -.ui-slider-handle { - left: -5px !important; - border-radius: 8px !important; -cursor: pointer !important; -border: 1px solid #888 !important; -box-shadow: inset 0px 1px 0px #fff, 0px 0px 1px #777; -background-color: #dcdcdc !important; -/* -background: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#ccc)) !important; - background: -moz-linear-gradient(top, #777, #555) !important; - background: -o-linear-gradient(top, #777, #555) !important; - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#777777', endColorstr='#555555') !important; - */ -height: 14px !important; -width: 14px !important; -cursor: pointer !important; - } -.ui-slider-handle:focus { - outline: none; -} -.ui-slider-range { - border-radius: 10px !important; - box-shadow: inset 2px 0px 5px #222; - - background: -webkit-gradient(linear, left top, left bottom, from(#777), to(#555)) !important; - background: -moz-linear-gradient(top, #777, #555) !important; - background: -o-linear-gradient(top, #777, #555) !important; - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#777777', endColorstr='#555555') !important; - left: -1px !important; - bottom: -1px !important; - border: 1px solid #222 !important; -} - -/* -------------------------------------- */ -/* --------- Console ------------*/ -#console { - top: 35px; - left: 250px; - height: 266px; - width: 700px; - float: left; - background-color: #333; - font: 14px Courier; - color: #eee; - padding: 10px; - overflow: auto; - word-wrap: break-word; -} -/* -------------------------------- */ -.phone_screen_1 { - width: 151px; - background: #deeeff; - float: left; - margin: 2px 0 0 0; - font: 22px Arial; - border: 1px solid #b7babc; - border-bottom: none; - color: #5a5a5a; - outline: none; - line-height: 22px; -} -.phone_screen_2 { - width: 152px; - height: 90px; - background: #deeeff; - float: left; - margin: 0 0 -1px 0; - font: 12px Arial; - border: 1px solid #b7babc; - border-top: none; - color: #5a5a5a; - outline: none; -} -.login_label { - float: left; - width: 100px; - height: 22px; - line-height: 22px; -} -.login_input { - float: left; - width: 100px; - height: 22px; -} - -.login_input input{ - width: 100px; -} -/* ---- Additional styles ---- */ -#auto_login_token { - width: 0; - height: 0; - margin: 0; - padding: 0; - border: none; -} - -/* -------------- Z indexes -------------*/ -/*#phoneDiv { - z-index: 12; -} -*/ -#incomingDiv { - z-index: 14; -} -#connectingDiv { - z-index: 15; -} -#settingsDiv { - z-index: 17; -} -#messageDiv { - z-index: 18; -} -#loginDiv { - z-index: 19; -} -#video_requestUnmuteDiv { - z-index: 20; -} -#chatDiv { - z-index: 21; -} - -#transfer { - z-index: 22; -} -#infoDiv { - z-index: 30; -} -#micBack, #speakerBack{ - z-index: 100; -} -.iconBackgroundPressed{ - z-index: 101; -} -.closeButton { - z-index: 101; -} - diff --git a/client/client/src/styles/style_html_c2c.css b/client/client/src/styles/style_html_c2c.css deleted file mode 100644 index 1b5bd0aa..00000000 --- a/client/client/src/styles/style_html_c2c.css +++ /dev/null @@ -1,665 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and -MPL license for Flashphoner buyers. Other license versions by negatiation. -Write us support@flashphoner.com with any questions. -*/ - -body { - font: 12px Arial; - margin: 0; - background-color: #555; -} -img { - border: 0; -} - -/* -------------- Main click2call view ------------- */ -#c2c { - position: absolute; - height: 240px; - width: 320px; - position: relative; - background: #555; - border: 1px solid #111; - box-shadow: inset 0px 1px 0px #777, 0px 1px 0px #666; - top: 10px; - left: 10px; - /* - background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#555)); - background: -moz-linear-gradient(top, #555, #444); - background: -o-linear-gradient(top, #555, #444); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#444444'); - */ - border-radius: 6px; -} -.caller { - position: absolute; - top: 65px; - font: 50px Arial; - color: #fff; - float: left; - text-align: center; - width: 100%; - text-shadow: 0 1px black; -} -#callState { - position: absolute; - width: 100%; - text-align: center; - top: 125px; - font: 30px Arial; - color: #777; - text-shadow: 0 1px black; -} -/* ------------ Buttons ------------- */ -#buttonsPanel { - height: 40px; - /*background: #444;*/ - border: 1px solid #111; - border-right: none; - border-left: none; - position: absolute; - bottom: -1px; - width: 320px; - box-shadow: inset 0px 1px 0px #777; - /*0px 1px 0px #666*/ - background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#444)); - background: -moz-linear-gradient(top, #555, #444); - background: -o-linear-gradient(top, #555, #444); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#444444'); - border-radius: 0 0 6px 6px; -} - -.button { - position: absolute; - width: 36px; - height: 24px; - font: 13px Lucida Grande, Lucida Sans Unicode; - border: 1px solid #111; - color: #aaa; - text-shadow: 0px 1px 0 #000; - box-shadow: 0px 1px 0px #666, inset 0px 1px 0px #777; - text-align: center; - border-radius: 6px; - cursor: pointer; - background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#444)); - background: -moz-linear-gradient(top, #555555, #444444); - background: -o-linear-gradient(top, #555555, #444444); - background: -ms-linear-gradient(top, #555555, #444444); - -pie-background: linear-gradient(#555555, #444444); - line-height: 24px; - background-position: 55% center; - background-repeat: no-repeat; - behavior: url(assets/pie/PIE.htc); -} - - -#micButton, #cameraButton, #soundButton, #dialpadButton { - top: 8px; -} - -.call, .hangup { - border-radius: 12px; - color: white; - bottom: 7px; - left: 92px; - width: 134px; -} -.call { - background: -webkit-gradient(linear, left top, left bottom, from(#3b3), to(#0a0)); - background: -moz-linear-gradient(top, #3b3, #0a0); - background: -o-linear-gradient(top, #3b3, #0a0); - /*filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#33bb33', endColorstr='#00aa00');*/ - -pie-background: linear-gradient(#33bb33, #00aa00); - box-shadow: 0px 1px 0px #666, inset 0px 1px 0px #0f0; - color: #004400; - text-shadow: 0px 1px 0px #0d0; -} -.hangup { - background: -webkit-gradient(linear, left top, left bottom, from(#f33), to(#c00)); - background: -moz-linear-gradient(top, #f33, #c00); - background: -o-linear-gradient(top, #f33, #c00); - /*filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#ff3333', endColorstr='#cc0000');*/ - -pie-background: linear-gradient(#ff3333, #cc0000); - box-shadow: 0px 1px 0px #666, inset 0px 1px 0px #f66; - color: #600; - text-shadow: 0px 1px 0 #f33; - -} -.pressed { - border-color: #222; - border-bottom-color: #666; - box-shadow: inset 0px 1px 6px #111; - height: 25px; - line-height: 29px; - background-position-y: 63%; -} - -.disabled { - opacity: 0.5; -} -#micButton { - left: 6px; - background-image: url('../assets/c2c_mic.png'); - -pie-background: url(assets/c2c_mic.png) no-repeat center, linear-gradient(#555555, #444444); - background-position-x: 50%; -} - -#cameraButton { - right: 49px; - background-image: url('../assets/c2c_camera.png'); - -pie-background: url(assets/c2c_camera.png) no-repeat center, linear-gradient(#555555, #444444); -} -#soundButton { - left: 49px; - background-image: url('../assets/c2c_sound.png'); - -pie-background: url(assets/c2c_sound.png) no-repeat center, linear-gradient(#555555, #444444); -} -#dialpadButton { - right: 6px; - background-image: url('../assets/c2c_dialpad.png'); - -pie-background: url(assets/c2c_dialpad.png) no-repeat center, linear-gradient(#555555, #444444); -} -#hangupButton { -} -#callMeButton1, #callMeButton2, #callMeButton3 { - top: 340px; - left: 75px; - width: 180px; -} - -#callMeButton2 { - top: 380px; -} - -#callMeButton3 { - top: 420px; -} - -#aboutCallMe { - font: 14px Courier; - color: #eee; - position: absolute; - top: 460px; - left: 13px; - width: 326px; -} - -#c2c-test { -width: 200px; -height: 200px; -} -/* ---------- Dialpad ---------- */ -.dialPad { - position: absolute; - font: 13px Lucida Grande, Lucida Sans Unicode; - border: 1px solid #111; - color: #aaa; - text-shadow: 0px 1px 0 #000; - text-align: center; - border-radius: 4px; - cursor: pointer; - /* backs */ - background: -webkit-gradient(linear, left top, left bottom, from(#555), to(#444)); - background: -moz-linear-gradient(top, #555, #444); - background: -o-linear-gradient(top, #555, #444); - /*filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#444444');*/ - -pie-background: linear-gradient(#555, #444); - line-height: 20px; - width: 129px; - height: 152px; - bottom: 38px; - right: 6px; - box-shadow: 0px 0px 10px #222, inset 0px 1px 0px #777; - display: none; - behavior: url(assets/pie/PIE.htc); -} -.dialButton { - position: relative; - margin: 3px 0 0 4px; - float: left; - color: #ccc; -} -.dialButtonLine { - float: left; - height: 30px; -} -.dialScreen { - width: 117px; - height: 20px; - color: white; - text-shadow: none; - float: left; - margin: 4px 4px 2px 4px; - padding: 1px 2px 0 2px; - text-align: right; - font: bolder 18px Arial; - background-color: #000; - border-radius: 4px; - overflow: hidden; -} -/* ----------------------------- */ -/* ----------- Slider -------------- */ -#micSlider, #speakerSlider { - position: absolute; - top: -90px; - display: none; -} -#micBack, #speakerBack { -/* TODO replace sliders within sliderbackground*/ - position: absolute; - bottom: 38px; - width: 27px; - height: 102px; - background: #555; - box-shadow: inset 0px 1px 0px #777, 0px 2px 10px #222; - display: none; - border-radius: 4px; - border: 1px solid #111; - behavior: url(assets/pie/PIE.htc); -} -#micBack { - left: 11px; -} -#speakerBack { - left: 54px; -} -#micSlider { - left: 21px; -} -#speakerSlider { - left: 64px; -} -.ui-slider-vertical { - width: 7px !important; - height: 80px !important; - border: 1px solid #222 !important; - background-color: #555 !important; - box-shadow: inset 0px 0px 3px #111; -} -.ui-slider-handle { - left: -5px !important; - border-radius: 10px !important; - cursor: pointer !important; - border: 1px solid #222 !important; - box-shadow: 0px 0px 10px #333; - background: -webkit-gradient(linear, left top, left bottom, from(#777), to(#555)) !important; - background: -moz-linear-gradient(top, #777, #555) !important; - background: -o-linear-gradient(top, #777, #555) !important; - /*filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#777777', endColorstr='#555555') !important;*/ - -pie-background: linear-gradient (#777, #555) !important; - behavior: url(assets/pie/PIE.htc); -} -.ui-slider-handle:focus { - outline: none; -} -.ui-slider-range { - border-radius: 10px !important; - box-shadow: inset 2px 0px 5px #0f0; - background: -webkit-gradient(linear, left top, left bottom, from(#3b3), to(#0a0)) !important; - background: -moz-linear-gradient(top, #3b3, #0a0) !important; - background: -o-linear-gradient(top, #3b3, #0a0) !important; - /*filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#33bb33', endColorstr='#00aa00') !important;*/ - -pie-background: linear-gradient (#33bb33, #00aa00) !important; - behavior: url(assets/pie/PIE.htc); -} -/* --------------- Flash ---------------- */ -#flash { - overflow: hidden; - position: absolute; -} -#video { - height: 138px; - position: absolute; - top: 0px; - right: 0px; -} -.security { - position: absolute; - top: 60px; - left: 52px; - overflow: hidden; - width: 215px; - height: 140px; - visibility: visible; -} -.init { - width: 1px; - height: 1px; - visibility: hidden; -} -/* screen for showing both videos - my and interlocutor */ -.video { - width: 320px; - height: 240px; - background: #666; - position: absolute; - top: 0; - right: 0; - -} -/* screen only for my video */ -.videoMy { - position: absolute; - width: 80px; - height: 60px; - top: 0px; - right: 0px; - /*background: #666;*/ - /*box-shadow: 0px 0px 5px #111;*/ - border: 1px solid #222; -} -.sendVideoButton { - width: 30px; - height: 30px; - position: absolute; - top: 17px; - left: 265px; - opacity: 0.7; - display: none; -} -.sendVideoButtonPressed { - width: 20px; - height: 20px; - top: 22px; - left: 270px; -} -.sendVideoButton img { - width: 100%; - height: 100%; -} -/* ------------- Request ------------ */ -.request { - /*background: #555;*/ - position: absolute; - font: 20px Arial; - color: #fff; - text-shadow: 0 1px black; - top: 20px; - left: 20px; - width: 280px; - height: 180px; - text-align: center; - padding-top: 10px; - background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#555)); - background: -moz-linear-gradient(top, #666, #555); - background: -o-linear-gradient(top, #666, #555); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#555555'); - box-shadow: 0px 0px 10px #222, inset 0px 1px 0px #777; - border-radius: 4px; - display: none; - border: 1px solid #000; -} -.back { - position: absolute; - width: 320px; - height: 240px; - opacity: 0.4; - top: 0px; - left: 0px; - background-color: #555; - display: none; -} -/* ------------- Connecting ----------- */ -#connectingDiv { - position: absolute; - top: 125px; - width: 320px; - font: 30px Arial; - color: #777; - text-align: center; - text-shadow: 0 1px black; -} -#connectingText { -} -/* -------------------------------------- */ -/* ---------- Border ------------ */ -#settingsDiv, #infoDiv, #connectingDiv, #flash { - border-width: 2px 5px 5px\0/; - /*only for ie8*/ - border-style: solid\0/; - /*only for ie8*/ - border-color: #ddd\0/; - /*only for ie8*/ -} -#connectingDiv, #infoDiv { - border-width: 5px\0/; - /*only for ie8*/ -} -/* ---------- Shadow ---------- */ -#settingsDiv, #infoDiv { - box-shadow: 0 0 10px black; - box-shadow: 0 0 10px rgba(0,0,0,0.5); - -moz-box-shadow: 0 0 10px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 0 10px rgba(0,0,0,0.5); -} -/* ----------------------------- */ -textarea, text, input { - outline: none; - -moz-appearance: none; -} -input::-webkit-input-placeholder { - color: #ccc; - font: 14px Arial; -} -#calleeText { - padding-left: 1px; -} - -#phoneDiv { - left: 30px; - height: 240px; - width: 147px; - padding: 10px; - position: relative; -} -#versionOfProduct { - position: absolute; - top: 2px; - left: 4px; - /*font: 20px Arial;*/ - color: #111; - text-shadow: #777 0px 1px; -} -/* ---------------- Buttons ---------------- */ -.closeButton { - background: url(../assets/close.png); - right: 3px; - opacity: 0.7; - position: absolute; - top: 3px; - width: 14px; - height: 14px; -} -/*.iconButton { - width: 16px; - height: 16px; - float: left; - /* -moz-opacity: 0.6; - -khtml-opacity: 0.6; - opacity: 0.6; -} -*/ -.closeButton { - background: url(../assets/close.png); - right: 3px; -} -/* ----------------------------------------- */ -/* ------------- ��������� �������� ------------ */ -.bar { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 20px; - background-color: #ddd; - cursor: move; - font: 12px Arial; - font-weight: bolder; - color: #999; - text-shadow: #fff 0px 1px; - line-height: 20px; - text-align: left; -} -/* ----------------------------------- */ -/* ------------- Settings ------------ */ - -#settingsButton, #settingsView, #settingsOkButton, #micSelector, #camSelector, -#settingsMicImage, #settingsCamImage { -position: absolute; -} - -#settingsView { - top: 54px; - left: 50px; - height: 113px; - width: 230px; - padding-top: 20px; -} -#settingsButton { - top: 19px; - left: 18px; - width: 140px; - visibility: hidden; -} -#settingsOkButton{ - top: 94px; - left: 72px; - width: 80px; -} -#micSelector{ - top: 18px; - left: 45px; - width: 170px; -} -#camSelector{ - top: 54px; - left: 45px; - width: 170px; -} -#settingsMicImage{ - top: 22px; - left: 14px; -} - -#settingsCamImage{ - top: 58px; - left: 15px; -} -/* -------------------------------------- */ -/* ------------------ Info ------------------------ */ -#infoDiv { - top: 50px; - height: auto; - width: 200px; - margin: 0 auto; - position: relative; - padding: 10px; - visibility: hidden; - font: 16px Arial; - color: #000000; - background-color: #FFFFFF; - text-align: center; - line-height: 30px; - -moz-opacity: 0.95; -/* Mozilla 1.6 */ - -khtml-opacity: 0.95; -/* Konqueror 3.1, Safari 1.1 */ - opacity: 0.95; -/* CSS3 - Mozilla 1.7b +, Firefox 0.9 +, Safari 1.2+, Opera 9+ */ -} -#infoText { -} -/* ------------ Flash div -------------- */ - -.closed { - width: 1px !important; - height: 1px !important; - visibility: hidden; -} - -#requestUnmuteText { - position: absolute; - text-align: center; - width: 100%; - font-weight: bolder; -} -#closeButton_video_requestUnmuteDiv { - background: url(../assets/close.png); - right: 3px; - opacity: 0.7; - position: absolute; - top: 3px; - width: 14px; - height: 14px; -} - -/* --------- Console ------------*/ -#console { - position: absolute; - top: 10px; - left: 340px; - height: 700px; - width: 700px; - float: left; - background-color: #555; - font: 14px Courier; - color: #eee; - padding: 10px; - overflow: auto; - word-wrap: break-word; - line-height: 18px; -} - -/* --------- Timer ------------*/ - -#timer { -position: absolute; -top: 170px; -left: 135px; -text-shadow: 0 1px black; -color: #999; -display: none; -} - -/* -------------- Z indexes -------------*/ - -#versionOfProduct { - z-index: 4; -} -.video, .videoMy { - z-index: 5; -} -/*#buttonsBack { - z-index: 6; -} -*/ -#micBack, #speakerBack { - z-index: 6; -} -.button, #buttonsPanel { - z-index: 7; -} -#micSlider, #speakerSlider, #dialPad { - z-index: 8; -} -.sendVideoButton, #sendVideoButtonImage { - z-index: 9; -} -.request { - z-index: 10; -} -.security { - z-index: 11; -} -.flash { -} \ No newline at end of file diff --git a/client/client/src/styles/style_jquery_ui_1.8.15.css b/client/client/src/styles/style_jquery_ui_1.8.15.css deleted file mode 100644 index ad0ea5ea..00000000 --- a/client/client/src/styles/style_jquery_ui_1.8.15.css +++ /dev/null @@ -1,565 +0,0 @@ -/* - jQuery UI CSS Framework 1.8.15 - - Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - Dual licensed under the MIT or GPL Version 2 licenses. - http://jquery.org/license - - http://docs.jquery.com/UI/Theming/API -*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } -.ui-helper-clearfix { display: inline-block; } -/* required comment for clearfix to work in Opera \*/ -* html .ui-helper-clearfix { height:1%; } -.ui-helper-clearfix { display:block; } -/* end clearfix */ -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - - -/* - * jQuery UI CSS Framework 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px - */ - - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } -.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } -.ui-widget-content a { color: #333333; } -.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } -.ui-widget-header a { color: #ffffff; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } -.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-off { background-position: -96px -144px; } -.ui-icon-radio-on { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } - -/* Overlays */ -.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } -.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* - * jQuery UI Resizable 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizable#theming - */ -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* - * jQuery UI Selectable 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectable#theming - */ -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } -/* - * jQuery UI Accordion 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion#theming - */ -/* IE/Win - Fix animation bug - #4615 */ -.ui-accordion { width: 100%; } -.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } -.ui-accordion .ui-accordion-li-fix { display: inline; } -.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } -.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } -.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } -.ui-accordion .ui-accordion-content-active { display: block; } -/* - * jQuery UI Autocomplete 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete#theming - */ -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.15 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} -/* - * jQuery UI Button 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button#theming - */ -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ -/* - * jQuery UI Dialog 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog#theming - */ -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } -/* - * jQuery UI Slider 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider#theming - */ -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; }/* - * jQuery UI Tabs 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } -/* - * jQuery UI Datepicker 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - display: none; /*sorry for IE5*/ - display/**/: block; /*sorry for IE5*/ - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -}/* - * jQuery UI Progressbar 1.8.15 - * - * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar#theming - */ -.ui-progressbar { height:2em; text-align: left; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file diff --git a/client/client/src/styles/trackbar.css b/client/client/src/styles/trackbar.css deleted file mode 100644 index 5b49022f..00000000 --- a/client/client/src/styles/trackbar.css +++ /dev/null @@ -1,100 +0,0 @@ -/* -Copyright (c) 2011 Flashphoner -All rights reserved. This Code and the accompanying materials -are made available under the terms of the GNU Public License v2.0 -which accompanies this distribution, and is available at -http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - -Contributors: - Flashphoner - initial API and implementation - -This code and accompanying materials also available under LGPL and MPL license for Flashphoner buyers. Other license versions by negatiation. Write us support@flashphoner.com with any questions. -*/ -table.trackbar div, table.trackbar td { - margin: 0; - padding: 0; -} -table.trackbar { - border-collapse: collapse; - border-spacing: 0; -} -table.trackbar img { - border: 0; -} -/* Styles */ -table.trackbar { - width: 250px; - margin: 10px 35px 0 45px; - background: repeat-x url(./imgtrackbar/b_bg_on.gif) top left; -} -table.trackbar .l { - width: 1%; - text-align: right; - font-size: 1px; - background: repeat-x url(./imgtrackbar/b_bg_off.gif) top left; -} -table.trackbar .l div { - position: relative; - width: 0; - text-align: right; - z-index: 500; - white-space: nowrap; -} -table.trackbar .l div img { - cursor: pointer; -} -table.trackbar .l div span { - position: absolute; - top: -12px; - right: 6px; - z-index: 1000; - font: 11px tahoma; - color: #000; -} -table.trackbar .l div span.limit { - text-align: left; - position: absolute; - top: -12px; - right: 100%; - z-index: 100; - font: 11px tahoma; - color: #D0D0D0; -} -table.trackbar .r { - position: relative; - width: 1%; - text-align: left; - font-size: 1px; - background: repeat-x url(./imgtrackbar/b_bg_off.gif) top right; - cursor: default; -} -table.trackbar .r div { - position: relative; - width: 0; - text-align: left; - z-index: 500; - white-space: nowrap; -} -table.trackbar .r div img { - cursor: pointer; -} -table.trackbar .r div span { - position: absolute; - top: -12px; - left: 6px; - z-index: 1000; - font: 11px tahoma; - color: #000; -} -table.trackbar .r div span.limit { - position: absolute; - top: -12px; - left: 100%; - z-index: 100; - font: 11px tahoma; - color: #D0D0D0; -} -table.trackbar .c { - font-size: 1px; - width: 100%; -} diff --git a/client/client/src/styles/verdana.ttf b/client/client/src/styles/verdana.ttf deleted file mode 100644 index 5a059d23..00000000 Binary files a/client/client/src/styles/verdana.ttf and /dev/null differ diff --git a/client/libs/Cairngorm.swc b/client/libs/Cairngorm.swc deleted file mode 100644 index 9a06b639..00000000 Binary files a/client/libs/Cairngorm.swc and /dev/null differ diff --git a/client/load_tool/.actionScriptProperties b/client/load_tool/.actionScriptProperties deleted file mode 100644 index 51f72318..00000000 --- a/client/load_tool/.actionScriptProperties +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/load_tool/.flexProperties b/client/load_tool/.flexProperties deleted file mode 100644 index f2072112..00000000 --- a/client/load_tool/.flexProperties +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/client/load_tool/.project b/client/load_tool/.project deleted file mode 100644 index f394664d..00000000 --- a/client/load_tool/.project +++ /dev/null @@ -1,25 +0,0 @@ - - - load_tool - - - - - - com.adobe.flexbuilder.project.flexbuilder - - - - - - com.adobe.flexbuilder.project.flexnature - com.adobe.flexbuilder.project.actionscriptnature - - - - bin-debug - 2 - DOCUMENTS/output/load_tool - - - diff --git a/client/load_tool/.settings/org.eclipse.core.resources.prefs b/client/load_tool/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index e5beadd8..00000000 --- a/client/load_tool/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,3 +0,0 @@ -#Thu Nov 11 15:11:51 NOVT 2010 -eclipse.preferences.version=1 -encoding/=utf-8 diff --git a/client/load_tool/build.properties b/client/load_tool/build.properties deleted file mode 100644 index ac9ae7a7..00000000 --- a/client/load_tool/build.properties +++ /dev/null @@ -1,3 +0,0 @@ -FLEX_HOME_WINDOWS=C:/Program Files/Adobe/Adobe Flash Builder 4/sdks/3.4 -FLEX_HOME_LINUX=/opt/flex_sdk_3 -TITLE=Flashphoner Load Tool Documentation diff --git a/client/load_tool/build.xml b/client/load_tool/build.xml deleted file mode 100644 index ddbbb049..00000000 --- a/client/load_tool/build.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/client/load_tool/html-template/AC_OETags.js b/client/load_tool/html-template/AC_OETags.js deleted file mode 100644 index 6366467e..00000000 --- a/client/load_tool/html-template/AC_OETags.js +++ /dev/null @@ -1,292 +0,0 @@ -// Flash Player Version Detection - Rev 1.6 -// Detect Client Browser type -// Copyright(c) 2005-2006 Adobe Macromedia Software, LLC. All rights reserved. -var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false; -var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false; -var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false; - -function ControlVersion() -{ - var version; - var axo; - var e; - - // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry - - try { - // version will be set for 7.X or greater players - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"); - version = axo.GetVariable("$version"); - } catch (e) { - } - - if (!version) - { - try { - // version will be set for 6.X players only - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); - - // installed player is some revision of 6.0 - // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29, - // so we have to be careful. - - // default to the first public version - version = "WIN 6,0,21,0"; - - // throws if AllowScripAccess does not exist (introduced in 6.0r47) - axo.AllowScriptAccess = "always"; - - // safe to call for 6.0r47 or greater - version = axo.GetVariable("$version"); - - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 4.X or 5.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = axo.GetVariable("$version"); - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 3.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3"); - version = "WIN 3,0,18,0"; - } catch (e) { - } - } - - if (!version) - { - try { - // version will be set for 2.X player - axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); - version = "WIN 2,0,0,11"; - } catch (e) { - version = -1; - } - } - - return version; -} - -// JavaScript helper required to detect Flash Player PlugIn version information -function GetSwfVer(){ - // NS/Opera version >= 3 check for Flash plugin in plugin array - var flashVer = -1; - - if (navigator.plugins != null && navigator.plugins.length > 0) { - if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) { - var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : ""; - var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description; - var descArray = flashDescription.split(" "); - var tempArrayMajor = descArray[2].split("."); - var versionMajor = tempArrayMajor[0]; - var versionMinor = tempArrayMajor[1]; - var versionRevision = descArray[3]; - if (versionRevision == "") { - versionRevision = descArray[4]; - } - if (versionRevision[0] == "d") { - versionRevision = versionRevision.substring(1); - } else if (versionRevision[0] == "r") { - versionRevision = versionRevision.substring(1); - if (versionRevision.indexOf("d") > 0) { - versionRevision = versionRevision.substring(0, versionRevision.indexOf("d")); - } - } else if (versionRevision[0] == "b") { - versionRevision = versionRevision.substring(1); - } - var flashVer = versionMajor + "." + versionMinor + "." + versionRevision; - } - } - // MSN/WebTV 2.6 supports Flash 4 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4; - // WebTV 2.5 supports Flash 3 - else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3; - // older WebTV supports Flash 2 - else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2; - else if ( isIE && isWin && !isOpera ) { - flashVer = ControlVersion(); - } - return flashVer; -} - -// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available -function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) -{ - versionStr = GetSwfVer(); - if (versionStr == -1 ) { - return false; - } else if (versionStr != 0) { - if(isIE && isWin && !isOpera) { - // Given "WIN 2,0,0,11" - tempArray = versionStr.split(" "); // ["WIN", "2,0,0,11"] - tempString = tempArray[1]; // "2,0,0,11" - versionArray = tempString.split(","); // ['2', '0', '0', '11'] - } else { - versionArray = versionStr.split("."); - } - var versionMajor = versionArray[0]; - var versionMinor = versionArray[1]; - var versionRevision = versionArray[2]; - - // is the major.revision >= requested major.revision AND the minor version >= requested minor - if (versionMajor > parseFloat(reqMajorVer)) { - return true; - } else if (versionMajor == parseFloat(reqMajorVer)) { - if (versionMinor > parseFloat(reqMinorVer)) - return true; - else if (versionMinor == parseFloat(reqMinorVer)) { - if (versionRevision >= parseFloat(reqRevision)) - return true; - } - } - return false; - } -} - -function AC_AddExtension(src, ext) -{ - var qIndex = src.indexOf('?'); - if ( qIndex != -1) - { - // Add the extention (if needed) before the query params - var path = src.substring(0, qIndex); - if (path.length >= ext.length && path.lastIndexOf(ext) == (path.length - ext.length)) - return src; - else - return src.replace(/\?/, ext+'?'); - } - else - { - // Add the extension (if needed) to the end of the URL - if (src.length >= ext.length && src.lastIndexOf(ext) == (src.length - ext.length)) - return src; // Already have extension - else - return src + ext; - } -} - -function AC_Generateobj(objAttrs, params, embedAttrs) -{ - var str = ''; - if (isIE && isWin && !isOpera) - { - str += ' '; - str += ''; - } else { - str += ' - - rtmfp://87.226.225.59:1935 - true - flashphoner_app - \ No newline at end of file diff --git a/client/load_tool/html-template/general.xml b/client/load_tool/html-template/general.xml deleted file mode 100644 index 3c3ad19d..00000000 --- a/client/load_tool/html-template/general.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - 1 - 10 - sip:2001@87.226.225.55,87.226.225.55,5060,2001 - sip:2002@87.226.225.55,87.226.225.55,5060,2002 - sip:2003@87.226.225.55,87.226.225.55,5060,2003 - sip:2004@87.226.225.55,87.226.225.55,5060,2004 - sip:2005@87.226.225.55,87.226.225.55,5060,2005 - sip:2006@87.226.225.55,87.226.225.55,5060,2006 - sip:2007@87.226.225.55,87.226.225.55,5060,2007 - sip:2008@87.226.225.55,87.226.225.55,5060,2008 - sip:2009@87.226.225.55,87.226.225.55,5060,2009 - sip:2010@87.226.225.55,87.226.225.55,5060,2010 - sip:2011@87.226.225.55,87.226.225.55,5060,2011 - sip:2012@87.226.225.55,87.226.225.55,5060,2012 - sip:2013@87.226.225.55,87.226.225.55,5060,2013 - sip:2014@87.226.225.55,87.226.225.55,5060,2014 - sip:2015@87.226.225.55,87.226.225.55,5060,2015 - sip:2016@87.226.225.55,87.226.225.55,5060,2016 - sip:2017@87.226.225.55,87.226.225.55,5060,2017 - sip:2018@87.226.225.55,87.226.225.55,5060,2018 - sip:2019@87.226.225.55,87.226.225.55,5060,2019 - sip:2020@87.226.225.55,87.226.225.55,5060,2020 - sip:2021@87.226.225.55,87.226.225.55,5060,2021 - sip:2022@87.226.225.55,87.226.225.55,5060,2022 - sip:2023@87.226.225.55,87.226.225.55,5060,2023 - sip:2024@87.226.225.55,87.226.225.55,5060,2024 - sip:2025@87.226.225.55,87.226.225.55,5060,2025 - sip:2026@87.226.225.55,87.226.225.55,5060,2026 - sip:2027@87.226.225.55,87.226.225.55,5060,2027 - sip:2028@87.226.225.55,87.226.225.55,5060,2028 - sip:2029@87.226.225.55,87.226.225.55,5060,2029 - sip:2030@87.226.225.55,87.226.225.55,5060,2030 - sip:2031@87.226.225.55,87.226.225.55,5060,2031 - sip:2032@87.226.225.55,87.226.225.55,5060,2032 - sip:2033@87.226.225.55,87.226.225.55,5060,2033 - sip:2034@87.226.225.55,87.226.225.55,5060,2034 - sip:2035@87.226.225.55,87.226.225.55,5060,2035 - sip:2036@87.226.225.55,87.226.225.55,5060,2036 - sip:2037@87.226.225.55,87.226.225.55,5060,2037 - sip:2038@87.226.225.55,87.226.225.55,5060,2038 - sip:2039@87.226.225.55,87.226.225.55,5060,2039 - sip:2040@87.226.225.55,87.226.225.55,5060,2040 - sip:2041@87.226.225.55,87.226.225.55,5060,2041 - sip:2042@87.226.225.55,87.226.225.55,5060,2042 - sip:2043@87.226.225.55,87.226.225.55,5060,2043 - sip:2044@87.226.225.55,87.226.225.55,5060,2044 - sip:2045@87.226.225.55,87.226.225.55,5060,2045 - sip:2046@87.226.225.55,87.226.225.55,5060,2046 - sip:2047@87.226.225.55,87.226.225.55,5060,2047 - sip:2048@87.226.225.55,87.226.225.55,5060,2048 - sip:2049@87.226.225.55,87.226.225.55,5060,2049 - sip:2050@87.226.225.55,87.226.225.55,5060,2050 - sip:2051@87.226.225.55,87.226.225.55,5060,2051 - sip:2052@87.226.225.55,87.226.225.55,5060,2052 - sip:2053@87.226.225.55,87.226.225.55,5060,2053 - sip:2054@87.226.225.55,87.226.225.55,5060,2054 - sip:2055@87.226.225.55,87.226.225.55,5060,2055 - sip:2056@87.226.225.55,87.226.225.55,5060,2056 - sip:2057@87.226.225.55,87.226.225.55,5060,2057 - sip:2058@87.226.225.55,87.226.225.55,5060,2058 - sip:2059@87.226.225.55,87.226.225.55,5060,2059 - sip:2060@87.226.225.55,87.226.225.55,5060,2060 - sip:2061@87.226.225.55,87.226.225.55,5060,2061 - sip:2062@87.226.225.55,87.226.225.55,5060,2062 - sip:2063@87.226.225.55,87.226.225.55,5060,2063 - sip:2064@87.226.225.55,87.226.225.55,5060,2064 - sip:2065@87.226.225.55,87.226.225.55,5060,2065 - sip:2066@87.226.225.55,87.226.225.55,5060,2066 - sip:2067@87.226.225.55,87.226.225.55,5060,2067 - sip:2068@87.226.225.55,87.226.225.55,5060,2068 - sip:2069@87.226.225.55,87.226.225.55,5060,2069 - sip:2070@87.226.225.55,87.226.225.55,5060,2070 - sip:2071@87.226.225.55,87.226.225.55,5060,2071 - sip:2072@87.226.225.55,87.226.225.55,5060,2072 - sip:2073@87.226.225.55,87.226.225.55,5060,2073 - sip:2074@87.226.225.55,87.226.225.55,5060,2074 - sip:2075@87.226.225.55,87.226.225.55,5060,2075 - sip:2076@87.226.225.55,87.226.225.55,5060,2076 - sip:2077@87.226.225.55,87.226.225.55,5060,2077 - sip:2078@87.226.225.55,87.226.225.55,5060,2078 - sip:2079@87.226.225.55,87.226.225.55,5060,2079 - sip:2080@87.226.225.55,87.226.225.55,5060,2080 - sip:2081@87.226.225.55,87.226.225.55,5060,2081 - sip:2082@87.226.225.55,87.226.225.55,5060,2082 - sip:2083@87.226.225.55,87.226.225.55,5060,2083 - sip:2084@87.226.225.55,87.226.225.55,5060,2084 - sip:2085@87.226.225.55,87.226.225.55,5060,2085 - sip:2086@87.226.225.55,87.226.225.55,5060,2086 - sip:2087@87.226.225.55,87.226.225.55,5060,2087 - sip:2088@87.226.225.55,87.226.225.55,5060,2088 - sip:2089@87.226.225.55,87.226.225.55,5060,2089 - sip:2090@87.226.225.55,87.226.225.55,5060,2090 - sip:2091@87.226.225.55,87.226.225.55,5060,2091 - sip:2092@87.226.225.55,87.226.225.55,5060,2092 - sip:2093@87.226.225.55,87.226.225.55,5060,2093 - sip:2094@87.226.225.55,87.226.225.55,5060,2094 - sip:2095@87.226.225.55,87.226.225.55,5060,2095 - sip:2096@87.226.225.55,87.226.225.55,5060,2096 - sip:2097@87.226.225.55,87.226.225.55,5060,2097 - sip:2098@87.226.225.55,87.226.225.55,5060,2098 - sip:2099@87.226.225.55,87.226.225.55,5060,2099 - sip:2100@87.226.225.55,87.226.225.55,5060,2100 - \ No newline at end of file diff --git a/client/load_tool/html-template/history/history.css b/client/load_tool/html-template/history/history.css deleted file mode 100644 index dbc47c61..00000000 --- a/client/load_tool/html-template/history/history.css +++ /dev/null @@ -1,6 +0,0 @@ -/* This CSS stylesheet defines styles used by required elements in a flex application page that supports browser history */ - -#ie_historyFrame { width: 0px; height: 0px; display:none } -#firefox_anchorDiv { width: 0px; height: 0px; display:none } -#safari_formDiv { width: 0px; height: 0px; display:none } -#safari_rememberDiv { width: 0px; height: 0px; display:none } diff --git a/client/load_tool/html-template/history/history.js b/client/load_tool/html-template/history/history.js deleted file mode 100644 index 669d4b64..00000000 --- a/client/load_tool/html-template/history/history.js +++ /dev/null @@ -1,669 +0,0 @@ -BrowserHistoryUtils = { - addEvent: function(elm, evType, fn, useCapture) { - useCapture = useCapture || false; - if (elm.addEventListener) { - elm.addEventListener(evType, fn, useCapture); - return true; - } - else if (elm.attachEvent) { - var r = elm.attachEvent('on' + evType, fn); - return r; - } - else { - elm['on' + evType] = fn; - } - } -} - -BrowserHistory = (function() { - // type of browser - var browser = { - ie: false, - firefox: false, - safari: false, - opera: false, - version: -1 - }; - - // if setDefaultURL has been called, our first clue - // that the SWF is ready and listening - //var swfReady = false; - - // the URL we'll send to the SWF once it is ready - //var pendingURL = ''; - - // Default app state URL to use when no fragment ID present - var defaultHash = ''; - - // Last-known app state URL - var currentHref = document.location.href; - - // Initial URL (used only by IE) - var initialHref = document.location.href; - - // Initial URL (used only by IE) - var initialHash = document.location.hash; - - // History frame source URL prefix (used only by IE) - var historyFrameSourcePrefix = 'history/historyFrame.html?'; - - // History maintenance (used only by Safari) - var currentHistoryLength = -1; - - var historyHash = []; - - var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash); - - var backStack = []; - var forwardStack = []; - - var currentObjectId = null; - - //UserAgent detection - var useragent = navigator.userAgent.toLowerCase(); - - if (useragent.indexOf("opera") != -1) { - browser.opera = true; - } else if (useragent.indexOf("msie") != -1) { - browser.ie = true; - browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4)); - } else if (useragent.indexOf("safari") != -1) { - browser.safari = true; - browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7)); - } else if (useragent.indexOf("gecko") != -1) { - browser.firefox = true; - } - - if (browser.ie == true && browser.version == 7) { - window["_ie_firstload"] = false; - } - - // Accessor functions for obtaining specific elements of the page. - function getHistoryFrame() - { - return document.getElementById('ie_historyFrame'); - } - - function getAnchorElement() - { - return document.getElementById('firefox_anchorDiv'); - } - - function getFormElement() - { - return document.getElementById('safari_formDiv'); - } - - function getRememberElement() - { - return document.getElementById("safari_remember_field"); - } - - // Get the Flash player object for performing ExternalInterface callbacks. - // Updated for changes to SWFObject2. - function getPlayer(id) { - if (id && document.getElementById(id)) { - var r = document.getElementById(id); - if (typeof r.SetVariable != "undefined") { - return r; - } - else { - var o = r.getElementsByTagName("object"); - var e = r.getElementsByTagName("embed"); - if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - } - } - else { - var o = document.getElementsByTagName("object"); - var e = document.getElementsByTagName("embed"); - if (e.length > 0 && typeof e[0].SetVariable != "undefined") { - return e[0]; - } - else if (o.length > 0 && typeof o[0].SetVariable != "undefined") { - return o[0]; - } - else if (o.length > 1 && typeof o[1].SetVariable != "undefined") { - return o[1]; - } - } - return undefined; - } - - function getPlayers() { - var players = []; - if (players.length == 0) { - var tmp = document.getElementsByTagName('object'); - players = tmp; - } - - if (players.length == 0 || players[0].object == null) { - var tmp = document.getElementsByTagName('embed'); - players = tmp; - } - return players; - } - - function getIframeHash() { - var doc = getHistoryFrame().contentWindow.document; - var hash = String(doc.location.search); - if (hash.length == 1 && hash.charAt(0) == "?") { - hash = ""; - } - else if (hash.length >= 2 && hash.charAt(0) == "?") { - hash = hash.substring(1); - } - return hash; - } - - /* Get the current location hash excluding the '#' symbol. */ - function getHash() { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - var idx = document.location.href.indexOf('#'); - return (idx >= 0) ? document.location.href.substr(idx+1) : ''; - } - - /* Get the current location hash excluding the '#' symbol. */ - function setHash(hash) { - // It would be nice if we could use document.location.hash here, - // but it's faulty sometimes. - if (hash == '') hash = '#' - document.location.hash = hash; - } - - function createState(baseUrl, newUrl, flexAppUrl) { - return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null }; - } - - /* Add a history entry to the browser. - * baseUrl: the portion of the location prior to the '#' - * newUrl: the entire new URL, including '#' and following fragment - * flexAppUrl: the portion of the location following the '#' only - */ - function addHistoryEntry(baseUrl, newUrl, flexAppUrl) { - - //delete all the history entries - forwardStack = []; - - if (browser.ie) { - //Check to see if we are being asked to do a navigate for the first - //history entry, and if so ignore, because it's coming from the creation - //of the history iframe - if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) { - currentHref = initialHref; - return; - } - if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) { - newUrl = baseUrl + '#' + defaultHash; - flexAppUrl = defaultHash; - } else { - // for IE, tell the history frame to go somewhere without a '#' - // in order to get this entry into the browser history. - getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl; - } - setHash(flexAppUrl); - } else { - - //ADR - if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) { - initialState = createState(baseUrl, newUrl, flexAppUrl); - } else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) { - backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl); - } - - if (browser.safari) { - // for Safari, submit a form whose action points to the desired URL - if (browser.version <= 419.3) { - var file = window.location.pathname.toString(); - file = file.substring(file.lastIndexOf("/")+1); - getFormElement().innerHTML = '
    '; - //get the current elements and add them to the form - var qs = window.location.search.substring(1); - var qs_arr = qs.split("&"); - for (var i = 0; i < qs_arr.length; i++) { - var tmp = qs_arr[i].split("="); - var elem = document.createElement("input"); - elem.type = "hidden"; - elem.name = tmp[0]; - elem.value = tmp[1]; - document.forms.historyForm.appendChild(elem); - } - document.forms.historyForm.submit(); - } else { - top.location.hash = flexAppUrl; - } - // We also have to maintain the history by hand for Safari - historyHash[history.length] = flexAppUrl; - _storeStates(); - } else { - // Otherwise, write an anchor into the page and tell the browser to go there - addAnchor(flexAppUrl); - setHash(flexAppUrl); - } - } - backStack.push(createState(baseUrl, newUrl, flexAppUrl)); - } - - function _storeStates() { - if (browser.safari) { - getRememberElement().value = historyHash.join(","); - } - } - - function handleBackButton() { - //The "current" page is always at the top of the history stack. - var current = backStack.pop(); - if (!current) { return; } - var last = backStack[backStack.length - 1]; - if (!last && backStack.length == 0){ - last = initialState; - } - forwardStack.push(current); - } - - function handleForwardButton() { - //summary: private method. Do not call this directly. - - var last = forwardStack.pop(); - if (!last) { return; } - backStack.push(last); - } - - function handleArbitraryUrl() { - //delete all the history entries - forwardStack = []; - } - - /* Called periodically to poll to see if we need to detect navigation that has occurred */ - function checkForUrlChange() { - - if (browser.ie) { - if (currentHref != document.location.href && currentHref + '#' != document.location.href) { - //This occurs when the user has navigated to a specific URL - //within the app, and didn't use browser back/forward - //IE seems to have a bug where it stops updating the URL it - //shows the end-user at this point, but programatically it - //appears to be correct. Do a full app reload to get around - //this issue. - if (browser.version < 7) { - currentHref = document.location.href; - document.location.reload(); - } else { - if (getHash() != getIframeHash()) { - // this.iframe.src = this.blankURL + hash; - var sourceToSet = historyFrameSourcePrefix + getHash(); - getHistoryFrame().src = sourceToSet; - } - } - } - } - - if (browser.safari) { - // For Safari, we have to check to see if history.length changed. - if (currentHistoryLength >= 0 && history.length != currentHistoryLength) { - //alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|")); - var flexAppUrl = getHash(); - if (browser.version < 528.16 /* Anything earlier than Safari 4.0 */) - { - // If it did change and we're running Safari 3.x or earlier, - // then we have to look the old state up in our hand-maintained - // array since document.location.hash won't have changed, - // then call back into BrowserManager. - currentHistoryLength = history.length; - flexAppUrl = historyHash[currentHistoryLength]; - } - - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - _storeStates(); - } - } - if (browser.firefox) { - if (currentHref != document.location.href) { - var bsl = backStack.length; - - var urlActions = { - back: false, - forward: false, - set: false - } - - if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) { - urlActions.back = true; - // FIXME: could this ever be a forward button? - // we can't clear it because we still need to check for forwards. Ugg. - // clearInterval(this.locationTimer); - handleBackButton(); - } - - // first check to see if we could have gone forward. We always halt on - // a no-hash item. - if (forwardStack.length > 0) { - if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) { - urlActions.forward = true; - handleForwardButton(); - } - } - - // ok, that didn't work, try someplace back in the history stack - if ((bsl >= 2) && (backStack[bsl - 2])) { - if (backStack[bsl - 2].flexAppUrl == getHash()) { - urlActions.back = true; - handleBackButton(); - } - } - - if (!urlActions.back && !urlActions.forward) { - var foundInStacks = { - back: -1, - forward: -1 - } - - for (var i = 0; i < backStack.length; i++) { - if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.back = i; - } - } - for (var i = 0; i < forwardStack.length; i++) { - if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) { - arbitraryUrl = true; - foundInStacks.forward = i; - } - } - handleArbitraryUrl(); - } - - // Firefox changed; do a callback into BrowserManager to tell it. - currentHref = document.location.href; - var flexAppUrl = getHash(); - if (flexAppUrl == '') { - //flexAppUrl = defaultHash; - } - //ADR: to fix multiple - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - pl[i].browserURLChange(flexAppUrl); - } - } else { - getPlayer().browserURLChange(flexAppUrl); - } - } - } - //setTimeout(checkForUrlChange, 50); - } - - /* Write an anchor into the page to legitimize it as a URL for Firefox et al. */ - function addAnchor(flexAppUrl) - { - if (document.getElementsByName(flexAppUrl).length == 0) { - getAnchorElement().innerHTML += "" + flexAppUrl + ""; - } - } - - var _initialize = function () { - if (browser.ie) - { - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html"); - } - } - historyFrameSourcePrefix = iframe_location + "?"; - var src = historyFrameSourcePrefix; - - var iframe = document.createElement("iframe"); - iframe.id = 'ie_historyFrame'; - iframe.name = 'ie_historyFrame'; - //iframe.src = historyFrameSourcePrefix; - try { - document.body.appendChild(iframe); - } catch(e) { - setTimeout(function() { - document.body.appendChild(iframe); - }, 0); - } - } - - if (browser.safari) - { - var rememberDiv = document.createElement("div"); - rememberDiv.id = 'safari_rememberDiv'; - document.body.appendChild(rememberDiv); - rememberDiv.innerHTML = ''; - - var formDiv = document.createElement("div"); - formDiv.id = 'safari_formDiv'; - document.body.appendChild(formDiv); - - var reloader_content = document.createElement('div'); - reloader_content.id = 'safarireloader'; - var scripts = document.getElementsByTagName('script'); - for (var i = 0, s; s = scripts[i]; i++) { - if (s.src.indexOf("history.js") > -1) { - html = (new String(s.src)).replace(".js", ".html"); - } - } - reloader_content.innerHTML = ''; - document.body.appendChild(reloader_content); - reloader_content.style.position = 'absolute'; - reloader_content.style.left = reloader_content.style.top = '-9999px'; - iframe = reloader_content.getElementsByTagName('iframe')[0]; - - if (document.getElementById("safari_remember_field").value != "" ) { - historyHash = document.getElementById("safari_remember_field").value.split(","); - } - - } - - if (browser.firefox) - { - var anchorDiv = document.createElement("div"); - anchorDiv.id = 'firefox_anchorDiv'; - document.body.appendChild(anchorDiv); - } - - //setTimeout(checkForUrlChange, 50); - } - - return { - historyHash: historyHash, - backStack: function() { return backStack; }, - forwardStack: function() { return forwardStack }, - getPlayer: getPlayer, - initialize: function(src) { - _initialize(src); - }, - setURL: function(url) { - document.location.href = url; - }, - getURL: function() { - return document.location.href; - }, - getTitle: function() { - return document.title; - }, - setTitle: function(title) { - try { - backStack[backStack.length - 1].title = title; - } catch(e) { } - //if on safari, set the title to be the empty string. - if (browser.safari) { - if (title == "") { - try { - var tmp = window.location.href.toString(); - title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#")); - } catch(e) { - title = ""; - } - } - } - document.title = title; - }, - setDefaultURL: function(def) - { - defaultHash = def; - def = getHash(); - //trailing ? is important else an extra frame gets added to the history - //when navigating back to the first page. Alternatively could check - //in history frame navigation to compare # and ?. - if (browser.ie) - { - window['_ie_firstload'] = true; - var sourceToSet = historyFrameSourcePrefix + def; - var func = function() { - getHistoryFrame().src = sourceToSet; - window.location.replace("#" + def); - setInterval(checkForUrlChange, 50); - } - try { - func(); - } catch(e) { - window.setTimeout(function() { func(); }, 0); - } - } - - if (browser.safari) - { - currentHistoryLength = history.length; - if (historyHash.length == 0) { - historyHash[currentHistoryLength] = def; - var newloc = "#" + def; - window.location.replace(newloc); - } else { - //alert(historyHash[historyHash.length-1]); - } - //setHash(def); - setInterval(checkForUrlChange, 50); - } - - - if (browser.firefox || browser.opera) - { - var reg = new RegExp("#" + def + "$"); - if (window.location.toString().match(reg)) { - } else { - var newloc ="#" + def; - window.location.replace(newloc); - } - setInterval(checkForUrlChange, 50); - //setHash(def); - } - - }, - - /* Set the current browser URL; called from inside BrowserManager to propagate - * the application state out to the container. - */ - setBrowserURL: function(flexAppUrl, objectId) { - if (browser.ie && typeof objectId != "undefined") { - currentObjectId = objectId; - } - //fromIframe = fromIframe || false; - //fromFlex = fromFlex || false; - //alert("setBrowserURL: " + flexAppUrl); - //flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ; - - var pos = document.location.href.indexOf('#'); - var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href; - var newUrl = baseUrl + '#' + flexAppUrl; - - if (document.location.href != newUrl && document.location.href + '#' != newUrl) { - currentHref = newUrl; - addHistoryEntry(baseUrl, newUrl, flexAppUrl); - currentHistoryLength = history.length; - } - }, - - browserURLChange: function(flexAppUrl) { - var objectId = null; - if (browser.ie && currentObjectId != null) { - objectId = currentObjectId; - } - pendingURL = ''; - - if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) { - var pl = getPlayers(); - for (var i = 0; i < pl.length; i++) { - try { - pl[i].browserURLChange(flexAppUrl); - } catch(e) { } - } - } else { - try { - getPlayer(objectId).browserURLChange(flexAppUrl); - } catch(e) { } - } - - currentObjectId = null; - }, - getUserAgent: function() { - return navigator.userAgent; - }, - getPlatform: function() { - return navigator.platform; - } - - } - -})(); - -// Initialization - -// Automated unit testing and other diagnostics - -function setURL(url) -{ - document.location.href = url; -} - -function backButton() -{ - history.back(); -} - -function forwardButton() -{ - history.forward(); -} - -function goForwardOrBackInHistory(step) -{ - history.go(step); -} - -//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); }); -(function(i) { - var u =navigator.userAgent;var e=/*@cc_on!@*/false; - var st = setTimeout; - if(/webkit/i.test(u)){ - st(function(){ - var dr=document.readyState; - if(dr=="loaded"||dr=="complete"){i()} - else{st(arguments.callee,10);}},10); - } else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){ - document.addEventListener("DOMContentLoaded",i,false); - } else if(e){ - (function(){ - var t=document.createElement('doc:rdy'); - try{t.doScroll('left'); - i();t=null; - }catch(e){st(arguments.callee,0);}})(); - } else{ - window.onload=i; - } -})( function() {BrowserHistory.initialize();} ); diff --git a/client/load_tool/html-template/history/historyFrame.html b/client/load_tool/html-template/history/historyFrame.html deleted file mode 100644 index 07e3806f..00000000 --- a/client/load_tool/html-template/history/historyFrame.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - Hidden frame for Browser History support. - - diff --git a/client/load_tool/html-template/swfobject.js b/client/load_tool/html-template/swfobject.js deleted file mode 100644 index 839d82f3..00000000 --- a/client/load_tool/html-template/swfobject.js +++ /dev/null @@ -1,4 +0,0 @@ -/* SWFObject v2.2 beta1 - is released under the MIT License -*/ -var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad'}}aa.outerHTML='"+af+"";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab accounts.loginLogoff && value <= accounts.loginLogoff+accounts.loginAction){ - Logger.info("value > accounts.loginLogoff && value <= accounts.loginLogoff+accounts.loginAction"); - for each (var call:Call in flashAPI.calls){ - if (call.state == Call.STATE_RING && call.incoming){ - Logger.info("call.state == Call.STATE_RING && call.incoming "+call.id); - if (accounts.callsOfTalkState/2 > accounts.maxCountCall){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - }else if (accounts.callsOfTalkState/2 < accounts.minCountCall){ - Application.application.logs += username+" - execute ANSWER for callId "+call.id+"\n"; - call.answer(); - }else{ - value = PhoneConfig.getRandomInt(1,100); - if (value <= accounts.incomAnswer){ - Application.application.logs += username+" - execute ANSWER for callId "+call.id+"\n"; - call.answer(); - }else if (value > accounts.incomAnswer && value <= accounts.incomAnswer+accounts.incomHangup){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - } - } - } else if (call.state == Call.STATE_RING && !call.incoming){ - Logger.info("call.state == Call.STATE_RING && !call.incoming: "+call.id); - value = PhoneConfig.getRandomInt(1,100); - if (value <= accounts.callHangup){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - } - } else if (call.state == Call.STATE_TALK){ - Logger.info("call.state == Call.STATE_TALK: "+call.id); - if (call.timeOfCall > accounts.minTimeCall){ - value = PhoneConfig.getRandomInt(1,100); - if (value <= accounts.talkHangup){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - }else if (value > accounts.talkHangup && value <= accounts.talkHangup+accounts.talkHolding){ - Application.application.logs += username+" - execute HOLDING for callId "+call.id+"\n"; - call.setStatusHold(true); - }else if (value > accounts.talkHangup+accounts.talkHolding && value <= accounts.talkHangup+accounts.talkHolding + accounts.talkTransfer){ - transfer(call); - }else if (PhoneConfig.VIDEO_ENABLED){ - if (value >accounts.talkHangup+accounts.talkHolding + accounts.talkTransfer && value < accounts.talkHangup+accounts.talkHolding + accounts.talkTransfer + accounts.talkStopStartVideo ){ - if (call.isVideoCall){ - call.setSendVideo(false); - }else{ - call.setSendVideo(true); - } - } - } - } - } else if (call.state == Call.STATE_HOLD && call.iHolded){ - Logger.info("call.state == Call.STATE_HOLD && call.iHolded: "+call.id); - value = PhoneConfig.getRandomInt(1,100); - if (value <= accounts.holdingHangup){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - }else if (value > accounts.holdingHangup && value <= accounts.holdingHangup+accounts.holdingUnhold){ - Application.application.logs += username+" - execute UNHOLDING for callId "+call.id+"\n"; - call.setStatusHold(false); - } - } else if (call.state == Call.STATE_HOLD && !call.iHolded){ - Logger.info("call.state == Call.STATE_HOLD && !call.iHolded: "+call.id); - value = PhoneConfig.getRandomInt(1,100); - if (value <= accounts.holdedHangup){ - Application.application.logs += username+" - execute hangup for callId "+call.id+"\n"; - call.hangup(); - }else if (value > accounts.holdedHangup && value <= accounts.holdedHangup+accounts.holdedTransfer){ - transfer(call); - } - } - - } - if (flashAPI.calls.length == 0){ - callToUser(); - } - } - } - } - - /** - * Stop execute flashphoner api commands - **/ - public function stopTest():void{ - timer.removeEventListener(TimerEvent.TIMER,timerHandler); - timer.stop(); - timer = null; - if (flashAPI.modelLocator.logged){ - flashAPI.logoff(); - } - } - } - -} \ No newline at end of file diff --git a/client/load_tool/src/Accounts.as b/client/load_tool/src/Accounts.as deleted file mode 100644 index 496bebb5..00000000 --- a/client/load_tool/src/Accounts.as +++ /dev/null @@ -1,283 +0,0 @@ -package -{ - import com.flashphoner.Logger; - import com.flashphoner.api.Call; - import com.flashphoner.api.Flash_API; - import com.flashphoner.api.data.PhoneConfig; - - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.events.SecurityErrorEvent; - import flash.events.TimerEvent; - import flash.net.URLLoader; - import flash.net.URLRequest; - import flash.sampler.startSampling; - import flash.utils.Timer; - - import mx.collections.ArrayCollection; - import mx.controls.Alert; - import mx.core.Application; - - - [Binable] - /** - * Class loading all Accounts and stores the probabilities of events - **/ - public class Accounts - { - - public var accounts:ArrayCollection = new ArrayCollection(); - - public static var allUsernames:ArrayCollection = new ArrayCollection(); - - private static var accountsObj:Accounts; - private var from:int; - private var to:int; - private var timer:Timer; - - /** - * Minimum count of calls - **/ - public var minCountCall:int = 8; - /** - * Maximum count of calls - **/ - public var maxCountCall:int = 12; - /** - * Minimum time of call - **/ - public var minTimeCall:int = 120; - /** - * Probability login -> logoff - **/ - public var loginLogoff:int = 0; - /** - * Probability login -> any action - **/ - public var loginAction:int = 0; - - /** - * Probability incomming call -> hangup call - **/ - public var incomHangup:int = 0; - /** - * Probability incomming call -> answer - **/ - public var incomAnswer:int = 0; - /** - * Probability call to user -> hangup - **/ - public var callHangup:int = 0; - - /** - * Probability talk -> hangup - **/ - public var talkHangup:int = 0; - /** - * Probability talk -> hold - **/ - public var talkHolding:int = 0; - /** - * Probability talk -> stop start video - **/ - public var talkStopStartVideo = 0; - /** - * Probability talk -> tranfer call - **/ - public var talkTransfer:int = 0; - - /** - * Probability holding call -> hangup - **/ - public var holdingHangup:int = 0; - /** - * Probability holding -> unhold - **/ - public var holdingUnhold:int = 0; - - /** - * Probability holded -> hangup - **/ - public var holdedHangup:int = 0; - /** - * Probability holded -> transfer - **/ - public var holdedTransfer:int = 0; - - /** - * Allow call himself - **/ - public var callMe:Boolean = false; - /** - * Data of current statistic - **/ - public var statisticCollection:ArrayCollection = new ArrayCollection(); - /** - * Count of calls in Talk state - **/ - public var callsOfTalkState:int = 0; - - /** - * Update data of statistic by all accounts - **/ - public function updateStatistic():void{ - statisticCollection.removeAll(); - statisticCollection.addItem({state:"accounts",count:accounts.length}); - var countLogoff:int = 0; - var countLogin:int = 0; - var countIncom:int = 0; - var countCall:int = 0; - var countTalk:int = 0; - var countHolding:int = 0; - var countHolded:int = 0; - var countAllCalls:int = 0; - var sendingVideo = 0; - for each (var temp:* in accounts){ - var account:Account = Account(temp); - if(account.flashAPI.modelLocator.logged){ - countLogin++; - }else{ - countLogoff++; - } - for each (var call:Call in account.flashAPI.calls){ - countAllCalls++; - if (call.state == Call.STATE_RING && call.incoming){ - countIncom++; - } else if (call.state == Call.STATE_RING && !call.incoming){ - countCall++; - } else if (call.state == Call.STATE_TALK){ - if (call.isVideoCall){ - sendingVideo++; - } - countTalk++; - } else if (call.state ==Call.STATE_HOLD && call.iHolded){ - countHolding++; - } else if (call.state ==Call.STATE_HOLD && call.iHolded){ - countHolded++; - } - } - } - callsOfTalkState = countTalk; - statisticCollection.addItem({state:"logoff",count:countLogoff}); - statisticCollection.addItem({state:"login",count:countLogin}); - statisticCollection.addItem({state:"allCalls",count:countAllCalls}); - statisticCollection.addItem({state:"incom",count:countIncom}); - statisticCollection.addItem({state:"call",count:countCall}); - statisticCollection.addItem({state:"talk",count:countTalk}); - statisticCollection.addItem({state:"sending video",count:sendingVideo}); - statisticCollection.addItem({state:"holding",count:countHolding}); - statisticCollection.addItem({state:"holded",count:countHolded}); - } - /** - * Get object of singelton - **/ - public static function getInstance():Accounts{ - if (accountsObj == null){ - accountsObj = new Accounts(); - accountsObj.startTimer(); - } - - return accountsObj; - } - /** - * Initialize accounts from file - * @param from from number in file - * @param to to number in file - **/ - public function initAccounts(from:int, to:int):void{ - this.from = from; - this.to = to; - var loader:URLLoader = new URLLoader(); - var qwe:Object = Application.application.parameters; - var config:String = "general.xml"; - var request:URLRequest = new URLRequest(config); - loader.load(request); - loader.addEventListener(Event.COMPLETE, onComplete); - loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,seurityErrorHandler); - loader.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler); - } - - private function seurityErrorHandler(event:SecurityErrorEvent):void{ - throw new Error(event.toString()); - } - - private function ioErrorHandler(event:IOErrorEvent):void{ - throw new Error(event.toString()); - } - - /** - * Handler on readed the data file - **/ - private function onComplete(event:Event):void - { - var loader:URLLoader = event.target as URLLoader; - if (loader != null) - { - var xml:XML = new XML(loader.data); - var from_A:int = int(xml.from); - var to_A:int = int(xml.to); - - for (var i:int = from_A; i <= to_A; i++){ - var temp:String = xml['account_'+i]; - var array:Array = temp.split(","); - Accounts.allUsernames.addItem(array[0]); - if (i >= from && i <= to){ - var account:Account = new Account(); - account.username = array[0]; - account.outboundProxy = array[1]; - account.port = array[2]; - account.password = array[3]; - Accounts.getInstance().accounts.addItem(account); - } - } - Application.application.accountsLoaded(); - } - else - { - Alert.show("Can not load xml settings. Default settings will be used.","",Alert.OK); - } - } - - /** - * Start load tool for all accounts - **/ - public function startTest():void{ - for each (var temp:* in accounts){ - var account:Account = temp as Account; - account.startTest(); - } - } - /** - * Stop load tool for all accounts - **/ - public function stopTest():void{ - for each (var temp:* in accounts){ - var account:Account = temp as Account; - account.stopTest(); - } - accounts = new ArrayCollection(); - allUsernames = new ArrayCollection(); - } - - /** - * Start timer for update statistics - **/ - public function startTimer():void{ - if (timer!=null){ - timer.removeEventListener(TimerEvent.TIMER,timerHandler); - timer.stop(); - timer = null; - } - timer = new Timer(500); - timer.addEventListener(TimerEvent.TIMER,timerHandler); - timer.start(); - } - /** - * Handler which execute update statistics - **/ - private function timerHandler(timeEvent:TimerEvent):void{ - updateStatistic(); - } - - } -} \ No newline at end of file diff --git a/client/load_tool/src/TestStabApplication.html b/client/load_tool/src/TestStabApplication.html deleted file mode 100644 index cdcd246f..00000000 --- a/client/load_tool/src/TestStabApplication.html +++ /dev/null @@ -1,41 +0,0 @@ - - - -Flash phone - - - - - -
    - - Get Adobe Flash player - -
    - - - - \ No newline at end of file diff --git a/client/load_tool/src/TestStabApplication.mxml b/client/load_tool/src/TestStabApplication.mxml deleted file mode 100644 index 17f67ce0..00000000 --- a/client/load_tool/src/TestStabApplication.mxml +++ /dev/null @@ -1,267 +0,0 @@ - - - - to){ - Alert.show("ERROR!!!","",Alert.OK); - return - } - try{ - var loginLogoff:int = int(textLoginLogoff.text); - var loginAction:int = int(textLoginAction.text); - - var incomHangup:int = int(textIncomHangup.text); - var incomAnswer:int = int(textIncomAnswer.text); - - var callHangup:int = int(textCallHangup.text); - - var talkHangup:int = int(textTalkHangup.text); - var talkHolding:int = int(textTalkHolding.text); - var talkTransfer:int = int(textTalkTransfer.text); - - var holdingHangup:int = int(textHoldingHangup.text); - var holdingUnhold:int = int(textHoldingUnhold.text); - - var holdedHangup:int = int(textHoldedHangup.text); - var holdedTransfer:int = int(textHoldedTransfer.text); - - var talkStopStartVideo = int(textTalkStopStartVideo.text); - }catch(error:Error){ - Alert.show("ERROR Weight!!!","",Alert.OK); - return; - } - if (loginLogoff+loginAction > 100){ - Alert.show("ERROR Free Weight!!!","",Alert.OK); - return; - } - if (incomHangup+incomAnswer > 100){ - Alert.show("ERROR Incom Weight!!!","",Alert.OK); - return; - } - if (callHangup > 100){ - Alert.show("ERROR Call Weight!!!","",Alert.OK); - return; - } - if (talkHangup + talkHolding + talkTransfer + talkStopStartVideo > 100){ - Alert.show("ERROR Talk Weight!!!","",Alert.OK); - return; - } - if (holdingHangup + holdingUnhold > 100){ - Alert.show("ERROR Holding Weight!!!","",Alert.OK); - return; - } - if (holdedHangup + holdedTransfer > 100){ - Alert.show("ERROR Holded Weight!!!","",Alert.OK); - return; - } - - var accounts:Accounts = Accounts.getInstance(); - - accounts.loginLogoff = loginLogoff; - accounts.loginAction = loginAction; - accounts.incomHangup = incomHangup; - accounts.incomAnswer = incomAnswer; - accounts.callHangup = callHangup; - accounts.talkHangup = talkHangup; - accounts.talkHolding= talkHolding; - accounts.talkTransfer= talkTransfer; - accounts.talkStopStartVideo = talkStopStartVideo; - - accounts.holdingHangup = holdingHangup; - accounts.holdingUnhold = holdingUnhold; - - accounts.holdedHangup = holdedHangup; - accounts.holdedTransfer = holdedTransfer; - - accounts.initAccounts(from,to); - buttonGetAccount.enabled = false; - textFrom.enabled = false; - textTo.enabled = false; - textLoginLogoff.enabled = false; - textLoginAction.enabled = false; - textIncomHangup.enabled = false; - textIncomAnswer.enabled = false; - textCallHangup.enabled = false; - - textTalkHangup.enabled = false; - textTalkHolding.enabled = false; - textTalkTransfer.enabled = false; - - textHoldingHangup.enabled = false; - textHoldingUnhold.enabled = false; - - textHoldedHangup.enabled = false; - textHoldedTransfer.enabled = false; - - checkBoxCallMe.enabled = false; - checkBoxEnableVideoCalls.enabled=false; - } - - private function onApplyParameters():void{ - try{ - var minCountCall:int = int(textMinCountCall.text); - var maxCountCall:int = int(textMaxCountCall.text); - var minTimeCall:int = int(textMinTimeCall.text); - }catch(error:Error){ - Alert.show("ERROR!!!","",Alert.OK); - return; - } - if (minCountCall > maxCountCall){ - Alert.show("ERROR!!!","",Alert.OK); - return - } - Accounts.getInstance().minCountCall = minCountCall; - Accounts.getInstance().maxCountCall = maxCountCall; - Accounts.getInstance().minTimeCall = minTimeCall; - } - - private function onStartTest():void{ - if (buttonStartTest.label == "Start"){ - Accounts.getInstance().startTest(); - buttonStartTest.label = "Stop"; - }else{ - Accounts.getInstance().stopTest(); - buttonStartTest.enabled = false; - buttonStartTest.label = "Start"; - buttonGetAccount.enabled = true; - textFrom.enabled = true; - textTo.enabled = true; - - textLoginLogoff.enabled = true; - textLoginAction.enabled = true; - - textIncomHangup.enabled = true; - textIncomAnswer.enabled = true; - - textCallHangup.enabled = true; - - textTalkHangup.enabled = true; - textTalkHolding.enabled = true; - textTalkTransfer.enabled = true; - - textHoldingHangup.enabled = true; - textHoldingUnhold.enabled = true; - - textHoldedHangup.enabled = true; - textHoldedTransfer.enabled = true; - - textTalkStopStartVideo.enabled=true; - checkBoxCallMe.enabled = true; - checkBoxEnableVideoCalls.enabled=true; - - } - } - - private function onChange():void{ - if (checkBoxCallMe.selected){ - Accounts.getInstance().callMe = true; - }else{ - Accounts.getInstance().callMe = false; - } - } - private function onChangeCheckBoxEnableVideoCalls():void{ - if (checkBoxEnableVideoCalls.selected){ - PhoneConfig.VIDEO_ENABLED=true; - } else{ - PhoneConfig.VIDEO_ENABLED=false; - } - } - - public function accountsLoaded():void{ - Application.application.logs += "Accounts loaded\n"; - buttonStartTest.enabled = true; - } - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/wcs_media_client/.idea/.name b/client/wcs_media_client/.idea/.name new file mode 100644 index 00000000..51db1bff --- /dev/null +++ b/client/wcs_media_client/.idea/.name @@ -0,0 +1 @@ +wcs_media_client \ No newline at end of file diff --git a/client/wcs_media_client/.idea/encodings.xml b/client/wcs_media_client/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/client/wcs_media_client/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/client/wcs_media_client/.idea/misc.xml b/client/wcs_media_client/.idea/misc.xml new file mode 100644 index 00000000..1162f438 --- /dev/null +++ b/client/wcs_media_client/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/client/wcs_media_client/.idea/modules.xml b/client/wcs_media_client/.idea/modules.xml new file mode 100644 index 00000000..7f8ada6a --- /dev/null +++ b/client/wcs_media_client/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client/wcs_media_client/.idea/scopes/scope_settings.xml b/client/wcs_media_client/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/client/wcs_media_client/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/client/wcs_media_client/.idea/vcs.xml b/client/wcs_media_client/.idea/vcs.xml new file mode 100644 index 00000000..def6a6a1 --- /dev/null +++ b/client/wcs_media_client/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/client/wcs_media_client/.idea/wcs_media_client.iml b/client/wcs_media_client/.idea/wcs_media_client.iml new file mode 100644 index 00000000..6b8184f8 --- /dev/null +++ b/client/wcs_media_client/.idea/wcs_media_client.iml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/client/wcs_media_client/.idea/workspace.xml b/client/wcs_media_client/.idea/workspace.xml new file mode 100644 index 00000000..db9497da --- /dev/null +++ b/client/wcs_media_client/.idea/workspace.xml @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1397103062857 + 1397103062857 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/wcs_media_client/css/styles.css b/client/wcs_media_client/css/styles.css new file mode 100644 index 00000000..2db7f4ff --- /dev/null +++ b/client/wcs_media_client/css/styles.css @@ -0,0 +1,503 @@ +publish-translation/*.video { + border: 1px solid; + height: 480px; + width: 640px; + padding: 10px 10px; + +}*/ + +.button { + background: #3498db; + background-image: -webkit-linear-gradient(top, #3498db, #2980b9); + background-image: -moz-linear-gradient(top, #3498db, #2980b9); + background-image: -ms-linear-gradient(top, #3498db, #2980b9); + background-image: -o-linear-gradient(top, #3498db, #2980b9); + background-image: linear-gradient(to bottom, #3498db, #2980b9); + -webkit-border-radius: 28; + -moz-border-radius: 28; + border-radius: 28px; + font-family: Arial; + color: #ffffff; + font-size: 12px; + padding: 10px 20px 10px 20px; + text-decoration: none; + display: inline; + opacity: 0; +} + +.button:hover { + background: #3cb0fd; + background-image: -webkit-linear-gradient(top, #3cb0fd, #3498db); + background-image: -moz-linear-gradient(top, #3cb0fd, #3498db); + background-image: -ms-linear-gradient(top, #3cb0fd, #3498db); + background-image: -o-linear-gradient(top, #3cb0fd, #3498db); + background-image: linear-gradient(to bottom, #3cb0fd, #3498db); + text-decoration: none; + cursor: pointer !important; +} + +.buttonDisabled { + background: #98989a; + background-image: -webkit-linear-gradient(top, #98989a, #717172); + background-image: -moz-linear-gradient(top, #98989a, #717172); + background-image: -ms-linear-gradient(top, #98989a, #717172); + background-image: -o-linear-gradient(top, #98989a, #717172); + background-image: linear-gradient(to bottom, #98989a, #717172); + -webkit-border-radius: 28; + -moz-border-radius: 28; + border-radius: 28px; + font-family: Arial; + color: #ffffff; + font-size: 12px; + padding: 10px 20px 10px 20px; + text-decoration: none; + display: inline; +} + +.info { + border: solid 1px; + height: 20px; + width: 640px; + background: #ccc; +} + +.textInput { + type: text-input; + width: 640px; + height: 20px; + font: Arial; + font-size: 12px; + border: solid 1px; +} + +.player-communication{ + background: linear-gradient(bottom, #191919 32%, #454545 93%); + background: -moz-linear-gradient(bottom, #191919 32%, #454545 93%); + background: -webkit-linear-gradient(bottom, #191919 32%, #454545 93%); + + width:100%; + height:100%; +} +.player-communication-2{ + background: linear-gradient(bottom, #191919 32%, #454545 93%); + background: -moz-linear-gradient(bottom, #191919 32%, #454545 93%); + background: -webkit-linear-gradient(bottom, #191919 32%, #454545 93%); + + width:100%; + height:100%; +} +.videoDiv{ + width:640px; + height:480px; + margin:0 auto; + border: 6px solid #191919; + border-radius: 5px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + position:relative; +} + +.video{ + width: 100%; + height: auto; + margin-top: 50px; +} +.flash-img{ + position:absolute; + top:8px; + left:8px; + height:28px; + width: 103px; + z-index:999; +} +.connect-translation{ + height: 100px; + left: 150px; + position: absolute; + top: 200px; + width: 335px; + display:none; +} +.connect-translation>span{ + color:#ffffff; + font:14px Arial; + display:block; + width:100%; +} +.connect-img{ + height: 44px; + width: 92px; + background-image:url(../images/start.png); + margin: 36px 0 0 121px; +} +.connect-img:hover{ + height: 44px; + width: 92px; + background-image:url(../images/start-hover.png); + +} +.connect-img:active{ + background-image:url(../images/start-click.png); +} +.access-video{ + display:none; + background:url(../images/access.png) no-repeat 0 0; + height: 322px; + left: 162px; + position: absolute; + top: 118px; + width: 318px; +} +.access-img{ + height: 44px; + width: 92px; + background-image:url(../images/acancel.png); + margin: 136px 0 0 109px; +} +.access-img:hover{ + height: 44px; + width: 92px; + background-image:url(../images/acancel-hover.png); +} +.access-img:active{ + background-image:url(../images/acancel-click.png); +} +.access-video>span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + margin: 128px 1px 2px 3px; + text-align: center; + width: 100%; +} +.preload-intro{ + display:none; + height: 150px; + left: 260px; + position: absolute; + top: 165px; + width: 120px; + z-index: 9999; +} +.preload-intro>span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + text-align: center; + width: 100%; +} +.preload-connect{ + display: none; + height: 353px; + left: 0; + position: absolute; + top: 127px; + width: 100%; +} +.preload-connect>img{ +margin: 67px 0 0 270px; +opacity: 0.5; +} +.panel-bottom{ + height: 33px; + margin-top: 137px; + padding-top: 15px; + width: 100%; + background: rgba(0,0,0,0.5); + position:relative; +} +.panel-bottom>span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + margin: 2px auto; + text-align: center; + width: 73px; +} +.panel-bottom>div{ + height: 29px; + margin-right: 14px; + margin-top: -29px; + width: 29px; +background:url(../images/stop1.png) no-repeat 9px 11px rgba(0, 0, 0, 0); +float:right; + +} +.panel-bottom>div:hover{ +background:url(../images/stop2.png); +} + +.publish-translation{ + display: none; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.publish-translation > .icon-translation{ + height: 31px; + width: 78%; + float:right; + background:url(../images/t-conect-x1.png) no-repeat center right; + +} +.publish-translation > .panel-translation{ + height: 41px; + margin-top: 439px; + background: none repeat scroll 0 0 rgba(0, 0, 0, 0.5); + width: 100%; + + +} +.publish-translation >.icon-translation > span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + margin-top: 9px; + text-align: center; + width: 490px; +} +.copy-code{ + background: url(../images/copy1.png); + width:596px; + height:100%; + display: inline-block; +} +.copy-code:hover{ + background: url(../images/copy2.png); +} +.copy-code > span{ + color: #000000; + display: inline-block; + float: left; + font: 12px verdana; + margin: 14px 0 0 27px; +} +.stop-x{ + background: url("../images/stop1.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + display: inline-block; + height: 100%; + width: 39px; + position:relative; +} +.stop-x:hover{ + background: url("../images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + +} +.stop-x:active{ + background: url("../images/stop3.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0); +} +.stop-x:visited{ + background: url("../images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0); +} +.black-window{ + position:absolute; + left:0; + top:0; + width:100%; + height:100%; + background: linear-gradient(bottom, #191919 32%, #454545 93%); + background: -moz-linear-gradient(bottom, #191919 32%, #454545 93%); + background: -webkit-linear-gradient(bottom, #191919 32%, #454545 93%); + display:none; +} + + +.visit-translation{ + display: none; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.panel-visit{ + height: 41px; + margin-top: 439px; + background: none repeat scroll 0 0 rgba(0, 0, 0, 0.5); + width: 100%; + +} +.icon-visit > span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + margin-top: 9px; + text-align: center; + width: 184px; +} +.visit-code{ + + width:556px; + height:100%; + display: inline-block; +} +.visit-code > span{ + color: #ffffff; + display: inline-block; + float: left; + font: 12px verdana; + margin: 14px 0 0 27px; +} +.stop-y{ + background:url(../images/stop1.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + width:30px; + height:100%; + display: inline-block; + position:relative; +} +.stop-y:hover{ + background:url(../images/stop2.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); +} +.ex-size{ + background:url(../images/fulla.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + width:30px; + height:100%; + display: inline-block; +} +.ex-size:hover{ + background:url(../images/fullb.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); +} +.ex-size-min{ + background:url(../images/mina.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + width:30px; + height:100%; + display: inline-block; +} +.ex-size-min:hover{ + background:url(../images/minb.png)no-repeat scroll 9px 11px rgba(0, 0, 0, 0); +} +.icon-visit{ + height: 31px; + width: 37%; + float:right; + background:url(../images/t-conect-x2.png) no-repeat center right; +} +.play-stop{ + display: none; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} +.button-play-stop{ + height: 100px; + margin: 198px auto 0; + width: 235px; +} +.button-play-stop>span{ + color: #ffffff; + display: inline-block; + text-align: center; + font: 12px verdana; + +} +.button-play-stop>div{ + background:url(../images/play.png); + height:35px; + width:32px; + margin:0 0 0 107px; +} +.button-play-stop>div:hover{ + background:url(../images/play-hover.png); + margin: 0 0 0 108px; +} +.info-anchor{ + width:100%; + height: 41px; + margin-top: 141px; + background: none repeat scroll 0 0 rgba(0, 0, 0, 0.5); +} +.info-anchor>span{ + color: #ffffff; + display: inline-block; + float: left; + font: 12px verdana; + margin: 14px 0 0 27px; +} +.full-align{ + width: 647px; + height:41px; + margin:0 auto; +} +.stop-text{ + background: url("../images/stop-text.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0); + height: 21px; + position: absolute; + right: 7777px; + top: -20px; + width: 28px; +} +.text-previu{ + width:640px; + margin:5px auto; +} +.text-previu>span{ + display: block; + font: 13px Verdana; + text-align: center; + width: 640px; + +} +.info-previu{ + width:640px; + margin:5px auto; +} +.info-previu>span{ + display: block; + font: 13px Verdana; + text-align: center; + width: 640px; + color: red; +} +.preload-visit{ + display: none; + height: 353px; + left: 0; + position: absolute; + top: 127px; + width: 100%; +} +.panel-bottom-visit{ + height: 33px; + margin-top: 137px; + padding-top: 15px; + width: 100%; + background: rgba(0,0,0,0.5); + position:relative; +} +.stop-z{ + background: url("../images/stop1.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0); + display: inline-block; + height: 100%; + width: 39px; + position:relative; +} + + +.preload-visit>img{ +margin: 67px 0 0 270px; +opacity: 0.5; +} +.panel-bottom-visit>span{ + color: #FFFFFF; + display: block; + font: 12px Arial; + margin: 2px auto; + text-align: center; + width: 73px; +} +.panel-bottom-visit>div{ + height: 29px; + margin-right: 14px; + margin-top: -29px; + width: 29px; +background:url(../images/stop1.png) no-repeat 9px 11px rgba(0, 0, 0, 0); +float:right; + +} +.panel-bottom-visit>div:hover{ +background:url(../images/stop2.png) no-repeat 9px 11px rgba(0, 0, 0, 0); +} diff --git a/client/wcs_media_client/flashphoner.xml b/client/wcs_media_client/flashphoner.xml new file mode 100644 index 00000000..4d0279ab --- /dev/null +++ b/client/wcs_media_client/flashphoner.xml @@ -0,0 +1,6 @@ + + 188.226.144.63 + 8080 + 1280 + 720 + \ No newline at end of file diff --git a/client/wcs_media_client/images/acancel-click.png b/client/wcs_media_client/images/acancel-click.png new file mode 100644 index 00000000..bc87b3af Binary files /dev/null and b/client/wcs_media_client/images/acancel-click.png differ diff --git a/client/wcs_media_client/images/acancel-hover.png b/client/wcs_media_client/images/acancel-hover.png new file mode 100644 index 00000000..d986f8d6 Binary files /dev/null and b/client/wcs_media_client/images/acancel-hover.png differ diff --git a/client/client/src/assets/c2c_hangup.png b/client/wcs_media_client/images/acancel.png similarity index 56% rename from client/client/src/assets/c2c_hangup.png rename to client/wcs_media_client/images/acancel.png index 26d50674..3edf9514 100644 Binary files a/client/client/src/assets/c2c_hangup.png and b/client/wcs_media_client/images/acancel.png differ diff --git a/client/wcs_media_client/images/access.png b/client/wcs_media_client/images/access.png new file mode 100644 index 00000000..a3714a2a Binary files /dev/null and b/client/wcs_media_client/images/access.png differ diff --git a/client/wcs_media_client/images/copy1.png b/client/wcs_media_client/images/copy1.png new file mode 100644 index 00000000..a33bf0a9 Binary files /dev/null and b/client/wcs_media_client/images/copy1.png differ diff --git a/client/wcs_media_client/images/copy2.png b/client/wcs_media_client/images/copy2.png new file mode 100644 index 00000000..16cf9fde Binary files /dev/null and b/client/wcs_media_client/images/copy2.png differ diff --git a/client/wcs_media_client/images/flashphoner.png b/client/wcs_media_client/images/flashphoner.png new file mode 100644 index 00000000..ed7792b5 Binary files /dev/null and b/client/wcs_media_client/images/flashphoner.png differ diff --git a/client/wcs_media_client/images/full-screen-text.png b/client/wcs_media_client/images/full-screen-text.png new file mode 100644 index 00000000..5786e3db Binary files /dev/null and b/client/wcs_media_client/images/full-screen-text.png differ diff --git a/client/client/src/assets/close.png b/client/wcs_media_client/images/fulla.png similarity index 81% rename from client/client/src/assets/close.png rename to client/wcs_media_client/images/fulla.png index a2d4b236..811bbf80 100644 Binary files a/client/client/src/assets/close.png and b/client/wcs_media_client/images/fulla.png differ diff --git a/client/wcs_media_client/images/fullb.png b/client/wcs_media_client/images/fullb.png new file mode 100644 index 00000000..5aa48ea6 Binary files /dev/null and b/client/wcs_media_client/images/fullb.png differ diff --git a/client/wcs_media_client/images/mina.png b/client/wcs_media_client/images/mina.png new file mode 100644 index 00000000..4f098a19 Binary files /dev/null and b/client/wcs_media_client/images/mina.png differ diff --git a/client/wcs_media_client/images/minb.png b/client/wcs_media_client/images/minb.png new file mode 100644 index 00000000..d7704919 Binary files /dev/null and b/client/wcs_media_client/images/minb.png differ diff --git a/client/wcs_media_client/images/minimize-text.png b/client/wcs_media_client/images/minimize-text.png new file mode 100644 index 00000000..a6bc5ac0 Binary files /dev/null and b/client/wcs_media_client/images/minimize-text.png differ diff --git a/client/wcs_media_client/images/play-hover.png b/client/wcs_media_client/images/play-hover.png new file mode 100644 index 00000000..c28511ae Binary files /dev/null and b/client/wcs_media_client/images/play-hover.png differ diff --git a/client/wcs_media_client/images/play.png b/client/wcs_media_client/images/play.png new file mode 100644 index 00000000..77b9dd5a Binary files /dev/null and b/client/wcs_media_client/images/play.png differ diff --git a/client/wcs_media_client/images/preloader.gif b/client/wcs_media_client/images/preloader.gif new file mode 100644 index 00000000..506f59c1 Binary files /dev/null and b/client/wcs_media_client/images/preloader.gif differ diff --git a/client/wcs_media_client/images/preloader2.gif b/client/wcs_media_client/images/preloader2.gif new file mode 100644 index 00000000..7ba4aebb Binary files /dev/null and b/client/wcs_media_client/images/preloader2.gif differ diff --git a/client/wcs_media_client/images/preloader3.gif b/client/wcs_media_client/images/preloader3.gif new file mode 100644 index 00000000..866de91f Binary files /dev/null and b/client/wcs_media_client/images/preloader3.gif differ diff --git a/client/wcs_media_client/images/start-click.png b/client/wcs_media_client/images/start-click.png new file mode 100644 index 00000000..88681171 Binary files /dev/null and b/client/wcs_media_client/images/start-click.png differ diff --git a/client/wcs_media_client/images/start-hover.png b/client/wcs_media_client/images/start-hover.png new file mode 100644 index 00000000..50586907 Binary files /dev/null and b/client/wcs_media_client/images/start-hover.png differ diff --git a/client/wcs_media_client/images/start.png b/client/wcs_media_client/images/start.png new file mode 100644 index 00000000..8d896de9 Binary files /dev/null and b/client/wcs_media_client/images/start.png differ diff --git a/client/wcs_media_client/images/stop-text.png b/client/wcs_media_client/images/stop-text.png new file mode 100644 index 00000000..64557fc0 Binary files /dev/null and b/client/wcs_media_client/images/stop-text.png differ diff --git a/client/client/src/assets/c2c_sound.png b/client/wcs_media_client/images/stop1.png similarity index 92% rename from client/client/src/assets/c2c_sound.png rename to client/wcs_media_client/images/stop1.png index d18fa88b..bb8305de 100644 Binary files a/client/client/src/assets/c2c_sound.png and b/client/wcs_media_client/images/stop1.png differ diff --git a/client/wcs_media_client/images/stop2.png b/client/wcs_media_client/images/stop2.png new file mode 100644 index 00000000..800996bf Binary files /dev/null and b/client/wcs_media_client/images/stop2.png differ diff --git a/client/wcs_media_client/images/stop3.png b/client/wcs_media_client/images/stop3.png new file mode 100644 index 00000000..8259ac89 Binary files /dev/null and b/client/wcs_media_client/images/stop3.png differ diff --git a/client/wcs_media_client/images/t-conect-x1.png b/client/wcs_media_client/images/t-conect-x1.png new file mode 100644 index 00000000..03786c61 Binary files /dev/null and b/client/wcs_media_client/images/t-conect-x1.png differ diff --git a/client/wcs_media_client/images/t-conect-x2.png b/client/wcs_media_client/images/t-conect-x2.png new file mode 100644 index 00000000..bfb5df36 Binary files /dev/null and b/client/wcs_media_client/images/t-conect-x2.png differ diff --git a/client/wcs_media_client/index.html b/client/wcs_media_client/index.html new file mode 100644 index 00000000..756ef9ba --- /dev/null +++ b/client/wcs_media_client/index.html @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + WebRTC Live Video And Broadcasting Client For Live events and Webinars + + + +
    + +
    +
    + + +
    + + +
    + + +
    +
    + + +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + +
    + + +
    + Processing... + +
    +
    +
    +
    +
    + + +
    + + +
    + Processing... + +
    +
    +
    +
    +
    + + +
    + + Connecting... +
    + + +
    +
    + +
    + + +
    + +
    +
    + + +
    + + + + + + +
    + +
    + + + + + + \ No newline at end of file diff --git a/client/client/src/js/rtc/Adapter.js b/client/wcs_media_client/js/Adapter.js similarity index 100% rename from client/client/src/js/rtc/Adapter.js rename to client/wcs_media_client/js/Adapter.js diff --git a/client/wcs_media_client/js/Config.js b/client/wcs_media_client/js/Config.js new file mode 100644 index 00000000..591fa032 --- /dev/null +++ b/client/wcs_media_client/js/Config.js @@ -0,0 +1,44 @@ +/** + * Created by nazar on 10.04.14. + */ +//Load xml config + +Config = function () { + this.wcsIP = null; + this.wsPort = "8080"; + this.videoWidth = 640; + this.videoHeight = 480; + + $.ajax({ + type: "GET", + url: "flashphoner.xml", + dataType: "xml", + success: this.parseFlashphonerXML, + context: this + }); +}; + +Config.prototype = { + + parseFlashphonerXML: function(xml) { + + var wcsIP = $(xml).find("wcs_server"); + if (wcsIP.length > 0) { + this.wcsIP = wcsIP[0].textContent; + } + + var wsPort = $(xml).find("ws_port"); + if (wsPort.length > 0) { + this.wsPort = wsPort[0].textContent; + } + + var videoWidth = $(xml).find("video_width"); + if (videoWidth.length > 0) { + this.videoWidth = videoWidth[0].textContent; + } + var videoHeight = $(xml).find("video_height"); + if (videoHeight.length > 0) { + this.videoHeight = videoHeight[0].textContent; + } + } +}; \ No newline at end of file diff --git a/client/wcs_media_client/js/Main.js b/client/wcs_media_client/js/Main.js new file mode 100644 index 00000000..17674611 --- /dev/null +++ b/client/wcs_media_client/js/Main.js @@ -0,0 +1,364 @@ +/** + * Created by nazar on 10.04.14. + */ + +/* init variables */ +config = null; +flashphoner = null; + +function onDisconnect() { + $("#subscribeButton").unbind("click"); + $("#publishButton").unbind("click"); + $('.preload-intro').css({'display': 'none'}); + $('.connect-img').css({'display': 'none'}); +} +function onConnect() { + $("#publishButton").click(publishButtonListener); + $("#subscribeButton").click(subscribeButtonListener); + $('.preload-intro').css({'display': 'none'}); + if ($('.player-communication-2').css('display') === 'none') { + $('.connect-translation').css({'display': 'block'}); + $('.text-previu>span').text('You have connected to Flashphoner WebRTC server. Would you like to start your stream?'); + } else { + setTimeout(subscribeButtonListener, 1000); + $('.preload-visit').css('display', 'block'); + textId(); + //$('.visit-translation').css('display','block'); + $('.connect-translation').css('display', 'none'); + $('.stop-y').click(function () { + + subscribeButtonListener(); + connectButtonListener; + $('.visit-translation').css('display', 'none'); + $('.black-window').css({'display': 'block'}); + $('.play-stop').css({'display': 'block'}); + $('.text-previu>span').text('Video is stopped. Would you like to continue playback?'); + $('.button-play-stop>div').click(function () { + connectButtonListener; + subscribeButtonListener(); + $('.black-window').css({'display': 'none'}); + $('.play-stop').css({'display': 'none'}); + $('.text-previu>span').text('Your stream is playing back'); + $('.visit-translation').css('display', 'block'); + + }); + }); + } + +} +connectButtonListener = function () { + console.log("Pressed connectButton"); + if ($('.flash-img').attr("flag") === 'ok') { + connect(); + $('.flash-img').attr("flag", "no"); + } else { + disconnect(); + $('.flash-img').attr("flag", "ok"); + } +}; + +function onPublish() { + $('.connect-translation').css({'display': 'none'}); + $('.connect-img').removeAttr('id'); + if ($('.flash-img').attr("connect-x") === "ok") { + $('.black-window').css({'display': 'none'}); + $('.access-video').css({'display': 'none'}); + $('.flash-img').attr("connect-x") === "no" + } else { + $('.access-video').css({'display': 'block'}); + $('.text-previu>span').text('You are trying to push a stream to Flashphoner WebRTC Server'); + } + $('.access-img').attr('id', 'publishButton'); + $("#subscribeButton").unbind("click"); + $("#publishButton").click(publishButtonListener); +} +function onUnpublish() { + $('.access-img').removeAttr('id'); + $('.access-video').css({'display': 'none'}); + $('.connect-translation').css({'display': 'block'}); + $('.text-previu>span').text('The publishing is stopped. Would you like to start stream again?'); + $('.connect-img').attr('id', 'publishButton'); + + if (flashphoner.isOpened) { + $("#subscribeButton").click(subscribeButtonListener); + //$('#subscribeButton').removeClass('buttonDisabled').addClass("button"); + } +} +publishButtonListener = function () { + console.log("Pressed publishButton"); + if ($('.connect-translation').css("display") === 'block') { + onPublish(); + publish(); + + } else { + onUnpublish(); + unpublish(); + } +}; + +function onSubscribe() { + $("#subscribeButton").text("Unsubscribe"); + + $("#publishButton").unbind("click"); + $('#publishButton').removeClass("button").addClass('buttonDisabled'); +} +function onUnsubscribe() { + $("#subscribeButton").text("Subscribe"); + if (flashphoner.isOpened) { + $("#publishButton").click(publishButtonListener); + $('#publishButton').removeClass('buttonDisabled').addClass("button"); + } +} +subscribeButtonListener = function () { + console.log("Pressed subscribeButton"); + if ($(".flash-img").attr('scrybe') === "ok") { + subscribe(); + onSubscribe(); + $(".flash-img").attr('scrybe', 'no'); + } else { + unsubscribe(); + onUnsubscribe(); + $(".flash-img").attr('scrybe', 'ok'); + } +}; +function parseUrlId() { + var idTrans = []; + var address = window.location.toString(); + var pattern = /https?:\/\/.*\?id\=(.*)/; + idTrans = address.match(pattern); + return idTrans[1]; +} +function loadWindow() { + var ads = window.location.toString(); + var pattern = /id\=[\w]+/g; + var idString = pattern.test(ads); + if (idString) { + return $('.player-communication').css({'display': 'none'}); + } else { + return $('.player-communication-2').css({'display': 'none'}); + } +} +function kindTrans() { + var ads = window.location.toString(); + var pattern = /id\=[\w]+/g; + var idString = pattern.test(ads); + return idString; +} + +/* onclick events */ +$(window).load(function () { + console.log("document ready"); + + loadWindow(); + var startConnect = setTimeout(connectButtonListener, 1000); + + $('.stop-x').hover( + function () { + $('.stop-x').css('background', 'url("images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + $('.stop-text').css('right', '7px'); + }, function () { + $('.stop-x').css('background', 'url("images/stop1.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + $('.stop-text').css('right', '7777px'); + }); + + $('.stop-x').mousedown(function () { + $('.stop-x').css('background', 'url("images/stop3.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + + }); + $('.stop-x').mouseup(function () { + $('.stop-x').css('background', 'url("images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + }); + + $('.stop-y').hover( + function () { + $('.stop-y').css('background', 'url("images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + $('.stop-text').css('right', '-2px'); + }, function () { + $('.stop-y').css('background', 'url("images/stop1.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + $('.stop-text').css('right', '7777px'); + }); + + $('.stop-y').mousedown(function () { + $('.stop-y').css('background', 'url("images/stop3.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + + }); + $('.stop-y').mouseup(function () { + $('.stop-y').css('background', 'url("images/stop2.png") no-repeat scroll 9px 11px rgba(0, 0, 0, 0)'); + }); +}); +function textId() { + var adress = window.location.toString(); + $('.visit-code>span').text(adress); + $('.info-anchor>span').text(adress); + $('.info-anchor>span').attr('data-clipboard-text', '' + adress + ''); + $('.visit-code>span').attr('data-clipboard-text', '' + adress + ''); +} +$(document).ready(function () { + var client3 = new ZeroClipboard($("#tarop"), { + moviePath: "js/ZeroClipboard.swf" + }); + var client4 = new ZeroClipboard($("#tarvisit"), { + moviePath: "js/ZeroClipboard.swf" + }); + + + config = new Config(); + flashphoner = new WebSocketManager(document.getElementById("localVideoPreview"), document.getElementById("remoteVideo")); + + $('.stop-x').click(function () { + //unpublish(); + publishButtonListener(); + // connectButtonListener; + $('.publish-translation').css('display', 'none'); + $('.black-window').css({'display': 'block'}); + $('.connect-translation').css({'display': 'block'}); + $('.text-previu>span').text('You are connected to server. Would you like to start stream?'); + }); +}); + + +function connect() { + info(""); + flashphoner.connect("ws://" + config.wcsIP + ":" + config.wsPort); + $('.preload-intro').css({'display': 'block'}); +} + +function disconnect() { + info(""); + flashphoner.disconnect(); +} + +function publish() { + info(""); + if (!hasAccess()) { + intervalId = setInterval('if (hasAccess()){clearInterval(intervalId); intervalId = -1; publish();}', 500); + flashphoner.getAccessToAudioAndVideo(); + } else { + flashphoner.publish(); + } +} + +function subscribe() { + info(""); + var codeText = parseUrlId(); + console.log("Streamname " + codeText); + if (codeText.indexOf("rtsp://") != -1) { + var url = codeText.split("&"); + flashphoner.prepareRtspSession(url[0]); + } else { + flashphoner.subscribe(codeText); + } + +} + +function unpublish() { + flashphoner.unpublish(); + setPublishStreamName(""); +} + +function unsubscribe() { + flashphoner.unSubscribe($("#streamName").text()); + setPublishStreamName(""); +} + +function hasAccess() { + return (flashphoner.hasAccessToAudio() && flashphoner.hasAccessToVideo()); +} +function siteName() { +// var name = []; +// var pattern = /(https?:\/\/[\w\.]+)/; +// var string = window.location.toString(); +// name = string.match(pattern); + return window.location.toString(); +} +function setPublishStreamName(text) { + + var addressId = window.location.toString() + '?id=' + text; + $("#publishStreamName").text(addressId); +} + +function info(text) { + console.log("INFO " + text); + $('.info-previu>span').text(text); +} + + +function notifySubscribeError(message) { + info(message); + flashphoner.closeMediaSession(); + onUnsubscribe(); +} + +function notifyPublishError(message) { + console.log("notifyPublishError"); + info(message); + flashphoner.closeMediaSession(); + onUnpublish(); +} + +function notifyOpenConnection() { + console.log("notifyOpenConnection"); + onConnect(); +} + +function notifyCloseConnection() { + console.log("notifyCloseConnection"); + onDisconnect(); + onUnpublish(); + onUnsubscribe(); + setPublishStreamName(""); +} + +function notifyConnectionError(message) { + info(message); + onDisconnect(); +} + +function notifyRtspError(message) { + info(message); + flashphoner.closeMediaSession(); + onUnsubscribe(); +} + +function notifyRtspReady(streamName) { + flashphoner.subscribe(streamName); +} + + +$(document).ready(function () { + + var client2 = new ZeroClipboard($(".copy-code"), { + moviePath: "js/ZeroClipboard.swf" + }); + client2.on("mouseover", function (client2) { + $('.copy-code').css('background', 'url("images/copy2.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code>span').css('background', '#ff5454'); + }); + client2.on("mouseout", function (client2) { + $('.copy-code').css('background', 'url("images/copy1.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code>span').css('background', '#ffffff'); + }); + client2.on("mousedown", function (client2) { + $('.copy-code').css('background', 'url("images/copy2.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code>span').css('background', '#ffffff'); + }); + client2.on("mouseup", function (client2) { + $('.copy-code').css('background', 'url("images/copy1.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code>span').css('background', '#ffffff'); + }); + client2.on("load", function (client2) { + $('.copy-code').css('background', 'url("images/copy1.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code').css('display', 'inline-block'); + $('.copy-code').css('height', '100%'); + $('.copy-code').css('width', '596px'); + $('.copy-code>span').css('background', '#ffffff'); + client2.on("complete", function (client2, args) { + $('.copy-code').css('background', 'url("images/copy2.png") no-repeat scroll 0 0 rgba(0, 0, 0, 0)'); + $('.copy-code').css('display', 'inline-block'); + $('.copy-code').css('height', '100%'); + $('.copy-code').css('width', '596px'); + $('.copy-code>span').css('background', '#ffffff'); + }); + }); +}); + diff --git a/client/client/src/js/rtc/WebRtcMediaManager.js b/client/wcs_media_client/js/WebRtcMediaManager.js similarity index 78% rename from client/client/src/js/rtc/WebRtcMediaManager.js rename to client/wcs_media_client/js/WebRtcMediaManager.js index ce8496b4..791680b0 100644 --- a/client/client/src/js/rtc/WebRtcMediaManager.js +++ b/client/wcs_media_client/js/WebRtcMediaManager.js @@ -9,13 +9,10 @@ var WebRtcMediaManager = function (localVideoPreview, remoteVideo) { me.localVideo.volume = 0; me.isAudioMuted = 1; me.isVideoMuted = 1; - //stun server by default - //commented to speedup WebRTC call establishment - //me.stunServer = "stun.l.google.com:19302"; }; WebRtcMediaManager.prototype.init = function () { - trace("WebRtcMediaManager - init"); + console.log("WebRtcMediaManager - init"); var me = this; me.hasVideo = false; @@ -26,11 +23,11 @@ WebRtcMediaManager.prototype.init = function () { WebRtcMediaManager.prototype.close = function () { //Commented to prevent termination of rtcMediaManager after MSRP call - trace("WebRtcMediaManager - close()"); + console.log("WebRtcMediaManager - close()"); if (this.peerConnectionState != 'finished') { this.peerConnectionState = 'finished'; if (this.peerConnection) { - trace("WebRtcMediaManager - PeerConnection will be closed"); + console.log("WebRtcMediaManager - PeerConnection will be closed"); this.peerConnection.close(); this.remoteVideo.pause(); this.remoteVideo.src = null; @@ -42,19 +39,11 @@ WebRtcMediaManager.prototype.close = function () { WebRtcMediaManager.prototype.createPeerConnection = function () { - trace("WebRtcMediaManager - createPeerConnection()"); + console.log("WebRtcMediaManager - createPeerConnection()"); var application = this; - if (webrtcDetectedBrowser == "firefox") { - pc_config = {"iceServers": [ - {"url": "stun:" + application.stunServer} - ]}; - } else { - pc_config = {"iceServers": [ - {"url": "stun:" + application.stunServer} - ]}; - } + pc_config = {"iceServers": []}; this.peerConnection = new RTCPeerConnection(pc_config, {"optional": [ - {"DtlsSrtpKeyAgreement": flashphonerLoader.useDTLS} + {"DtlsSrtpKeyAgreement": true} ]}); this.peerConnection.onaddstream = function (event) { @@ -68,9 +57,9 @@ WebRtcMediaManager.prototype.createPeerConnection = function () { }; WebRtcMediaManager.prototype.onOnAddStreamCallback = function (event) { - trace("WebRtcMediaManager - onOnAddStreamCallback(): event=" + event); - trace("WebRtcMediaManager - onOnAddStreamCallback(): event=" + event.stream); - trace("WebRtcMediaManager - onOnAddStreamCallback(): event=" + this.remoteVideo); + console.log("WebRtcMediaManager - onOnAddStreamCallback(): event=" + event); + console.log("WebRtcMediaManager - onOnAddStreamCallback(): event=" + event.stream); + console.log("WebRtcMediaManager - onOnAddStreamCallback(): event=" + this.remoteVideo); if (this.peerConnection != null) { this.remoteAudioVideoMediaStream = event.stream; attachMediaStream(this.remoteVideo, this.remoteAudioVideoMediaStream); @@ -81,7 +70,7 @@ WebRtcMediaManager.prototype.onOnAddStreamCallback = function (event) { }; WebRtcMediaManager.prototype.onOnRemoveStreamCallback = function (event) { - trace("WebRtcMediaManager - onOnRemoveStreamCallback(): event=" + event); + console.log("WebRtcMediaManager - onOnRemoveStreamCallback(): event=" + event); if (this.peerConnection != null) { this.remoteAudioVideoMediaStream = null; this.remoteVideo.pause(); @@ -95,9 +84,9 @@ WebRtcMediaManager.prototype.waitGatheringIce = function () { if (me.peerConnection != null) { sendSdp = function () { if (me.peerConnection != null) { - trace("WebRtcMediaManager - waitGatheringIce() iceGatheringState=" + me.peerConnection.iceGatheringState); + console.log("WebRtcMediaManager - waitGatheringIce() iceGatheringState=" + me.peerConnection.iceGatheringState); if (me.peerConnection.iceGatheringState == "complete") { - trace("WebRtcMediaManager - setLocalSDP: sdp=" + me.peerConnection.localDescription.sdp); + console.log("WebRtcMediaManager - setLocalSDP: sdp=" + me.peerConnection.localDescription.sdp); if (me.peerConnectionState == 'preparing-offer') { me.peerConnectionState = 'offer-sent'; me.createOfferCallback(me.peerConnection.localDescription.sdp);// + this.candidates); @@ -127,8 +116,14 @@ WebRtcMediaManager.prototype.waitGatheringIce = function () { WebRtcMediaManager.prototype.getAccessToAudioAndVideo = function () { var me = this; + var constrains = [ + {minWidth:config.videoWidth}, + {minHeight:config.videoHeight} + ]; if (!me.localAudioVideoStream) { - getUserMedia({audio: true, video: true}, function (stream) { + getUserMedia({audio: true, video: {mandatory:{}, optional:constrains}}, function (stream) { + document.getElementById('allow').style.display = "none"; + document.getElementById('preload-connect').style.display = "block";//Here is beginning of pre-loader attachMediaStream(me.localVideo, stream); me.localAudioVideoStream = stream; me.isAudioMuted = -1; @@ -159,20 +154,20 @@ WebRtcMediaManager.prototype.getAccessToAudio = function () { } }; -WebRtcMediaManager.prototype.createOffer = function (createOfferCallback, hasVideo) { - trace("WebRtcMediaManager - createOffer()"); +WebRtcMediaManager.prototype.createOffer = function (createOfferCallback, streamAudio, streamVideo) { + console.log("WebRtcMediaManager - createOffer()"); var me = this; try { if (me.getConnectionState() != "established") { - trace("Connection state is not established. Initializing..."); + console.log("Connection state is not established. Initializing..."); me.init(); } if (me.peerConnection == null) { - trace("peerConnection is null"); + console.log("peerConnection is null"); me.createPeerConnection(); - if (hasVideo) { + if (streamAudio && streamVideo) { me.peerConnection.addStream(me.localAudioVideoStream); - } else { + } else if (streamAudio) { me.peerConnection.addStream(me.localAudioStream); } } @@ -181,7 +176,7 @@ WebRtcMediaManager.prototype.createOffer = function (createOfferCallback, hasVid me.onCreateOfferSuccessCallback(offer); }, function (error) { me.onCreateOfferErrorCallback(error); - }); + }, {optional: [], mandatory: { OfferToReceiveAudio: true, OfferToReceiveVideo: true}}); } catch (exception) { @@ -191,7 +186,7 @@ WebRtcMediaManager.prototype.createOffer = function (createOfferCallback, hasVid WebRtcMediaManager.prototype.createAnswer = function (createAnswerCallback, hasVideo) { var me = this; - trace("WebRtcMediaManager - createAnswer() me.getConnectionState(): "+me.getConnectionState()+" me.hasVideo: "+me.hasVideo); + console.log("WebRtcMediaManager - createAnswer() me.getConnectionState(): " + me.getConnectionState() + " me.hasVideo: " + me.hasVideo); if (me.getConnectionState() != "established") { me.init(); } @@ -233,7 +228,7 @@ WebRtcMediaManager.prototype.createAnswer = function (createAnswerCallback, hasV }; WebRtcMediaManager.prototype.onCreateOfferSuccessCallback = function (offer) { - trace("WebRtcMediaManager - onCreateOfferSuccessCallback this.peerConnection: "+this.peerConnection+" this.peerConnectionState: "+this.peerConnectionState); + console.log("WebRtcMediaManager - onCreateOfferSuccessCallback this.peerConnection: " + this.peerConnection + " this.peerConnectionState: " + this.peerConnectionState); if (this.peerConnection != null) { if (this.peerConnectionState == 'new' || this.peerConnectionState == 'established') { var application = this; @@ -254,16 +249,16 @@ WebRtcMediaManager.prototype.onCreateOfferSuccessCallback = function (offer) { }; WebRtcMediaManager.prototype.onSetLocalDescriptionSuccessCallback = function (sdp) { - trace("WebRtcMediaManager - onSetLocalDescriptionSuccessCallback"); + console.log("WebRtcMediaManager - onSetLocalDescriptionSuccessCallback"); if (webrtcDetectedBrowser == "firefox") { - trace("WebRtcMediaManager - onSetLocalDescriptionSuccessCallback: sdp=" + sdp); + console.log("WebRtcMediaManager - onSetLocalDescriptionSuccessCallback: sdp=" + sdp); if (this.peerConnectionState == 'preparing-offer') { - trace("Current PeerConnectionState is 'preparing-offer' sending offer..."); + console.log("Current PeerConnectionState is 'preparing-offer' sending offer..."); this.peerConnectionState = 'offer-sent'; this.createOfferCallback(sdp); } else if (this.peerConnectionState == 'preparing-answer') { - trace("Current PeerConnectionState is 'preparing-answer' going to established..."); + console.log("Current PeerConnectionState is 'preparing-answer' going to established..."); this.peerConnectionState = 'established'; this.createAnswerCallback(sdp); } @@ -277,7 +272,7 @@ WebRtcMediaManager.prototype.getConnectionState = function () { }; WebRtcMediaManager.prototype.setRemoteSDP = function (sdp, isInitiator) { - trace("WebRtcMediaManager - setRemoteSDP: isInitiator: "+isInitiator+" sdp=" + sdp); + console.log("WebRtcMediaManager - setRemoteSDP: isInitiator: " + isInitiator + " sdp=" + sdp); if (isInitiator) { var sdpAnswer = new RTCSessionDescription({ type: 'answer', @@ -296,14 +291,19 @@ WebRtcMediaManager.prototype.setRemoteSDP = function (sdp, isInitiator) { }; WebRtcMediaManager.prototype.onSetRemoteDescriptionSuccessCallback = function () { - trace("onSetRemoteDescriptionSuccessCallback"); + console.log("onSetRemoteDescriptionSuccessCallback"); if (this.peerConnection != null) { if (this.peerConnectionState == 'answer-received') { - trace("Current PeerConnectionState is 'answer-received' changing the PeerConnectionState to 'established'"); + console.log("Current PeerConnectionState is 'answer-received' changing the PeerConnectionState to 'established'");//End of pre-loader + $('.preload-visit').css('display', 'none'); + if ($('.player-communication-2').css('display') !== 'none') { + $('.visit-translation').css('display', 'block'); + $('.text-previu>span').text('Your stream is playing back'); + } this.peerConnectionState = 'established'; } else if (this.peerConnectionState == 'offer-received') { - trace("Current PeerConnectionState is 'offer-received' creating appropriate answer..."); + console.log("Current PeerConnectionState is 'offer-received' creating appropriate answer..."); var application = this; this.peerConnection.createAnswer(function (answer) { application.onCreateAnswerSuccessCallback(answer); @@ -322,10 +322,10 @@ WebRtcMediaManager.prototype.onSetRemoteDescriptionSuccessCallback = function () WebRtcMediaManager.prototype.onCreateAnswerSuccessCallback = function (answer) { - trace("onCreateAnswerSuccessCallback "+this.peerConnection); + console.log("onCreateAnswerSuccessCallback " + this.peerConnection); if (this.peerConnection != null) { if (this.peerConnectionState == 'offer-received') { - trace("Current PeerConnectionState is 'offer-received', preparing answer..."); + console.log("Current PeerConnectionState is 'offer-received', preparing answer..."); // Prepare answer. var application = this; this.peerConnectionState = 'preparing-answer'; @@ -344,10 +344,6 @@ WebRtcMediaManager.prototype.onCreateAnswerSuccessCallback = function (answer) { } }; -WebRtcMediaManager.prototype.setStunServer = function (server) { - this.stunServer = server; -} - WebRtcMediaManager.prototype.onCreateAnswerErrorCallback = function (error) { console.error("WebRtcMediaManager - onCreateAnswerErrorCallback(): error: " + error); }; diff --git a/client/wcs_media_client/js/WebSocketManager.js b/client/wcs_media_client/js/WebSocketManager.js new file mode 100644 index 00000000..53fd779d --- /dev/null +++ b/client/wcs_media_client/js/WebSocketManager.js @@ -0,0 +1,237 @@ +/** + * Created by nazar on 10.04.14. + */ +var WebSocketManager = function (localVideoPreview, remoteVideo) { + var me = this; + + me.isOpened = false; + me.webSocket = null; + me.webRtcMediaManager = new WebRtcMediaManager(localVideoPreview, remoteVideo); + me.streamName = ""; + + this.callbacks = { + ping: function () { + me.webSocket.send("pong"); + }, + + setRemoteSDP: function (sdp, isInitiator) { + me.webRtcMediaManager.setRemoteSDP(sdp, isInitiator); + setPublishStreamName(me.streamName); + document.getElementById('preload-connect').style.display = "none"; + if(!kindTrans()){ + $('.publish-translation').css('display','block'); + $('.text-previu>span').text("You can share the stream using the link below. Press 'Copy' to copy the link to clipboard."); + $('.flash-img').attr("connect-x","ok"); + } + }, + + notifyVideoFormat: function (videoFormat) { + //notifyVideoFormat(videoFormat); + }, + + notifyAudioCodec: function (codec) { + }, + + notifySubscribeError: function (message) { + notifySubscribeError(message); + }, + + notifyPublishError: function (message) { + notifyPublishError(message); + }, + + notifyRtspError: function (message) { + notifyRtspError(message); + }, + + onReadyToPlay: function (streamName) { + notifyRtspReady(streamName); + }, + + notifyRtspSwitchingProtocols: function (streamName) { + console.log("notifyRtspSwitchingProtocols"); + me.unSubscribe(streamName); + } + + }; + +}; + +WebSocketManager.prototype = { + connect: function (WCSUrl) { + var me = this; + me.webSocket = $.websocket(WCSUrl, { + open: function () { + me.isOpened = true; + //fake login object + var loginObject = {}; + me.webSocket.send("connect", loginObject, "media"); + notifyOpenConnection(); + }, + close: function (event) { + me.isOpened = false; + if (!event.originalEvent.wasClean) { + console.dir("CONNECTION_ERROR"); + notifyConnectionError("CONNECTION_ERROR"); + } else { + notifyCloseConnection(); + me.webRtcMediaManager.close(); + } + }, + error: function () { + console.log("Error occured!"); + }, + context: me, + events: me.callbacks + }); + return 0; + }, + + disconnect: function () { + console.log("WebSocketManager - disconnect!"); + this.webSocket.close(); + }, + + publish: function () { + var me = this; + this.webRtcMediaManager.createOffer(function (sdp) { + var object = {}; + object.sdp = me.removeCandidatesFromSDP(sdp); + object.streamName = me.generateId(); + object.hasVideo = true; + me.streamName = object.streamName; + console.log("Publish streamName " + object.streamName); + me.webSocket.send("publish", object); + }, true, true); + }, + + unpublish: function (streamName) { + var me = this; + var object = {}; + if (streamName == "" || streamName == null) { + streamName = me.streamName; + } + object.streamName = streamName; + console.log("Unpublish stream " + streamName); + me.webSocket.send("unPublish", object); + me.streamName = ""; + me.webRtcMediaManager.close(); + }, + + subscribe: function (streamName) { + var me = this; + this.webRtcMediaManager.createOffer(function (sdp) { + var object = {}; + object.sdp = me.removeCandidatesFromSDP(sdp); + object.streamName = streamName; + object.hasVideo = true; + me.streamName = object.streamName; + console.log("subscribe streamName " + object.streamName); + me.webSocket.send("subscribe", object); + }, false, false); + }, + + unSubscribe: function (streamName) { + var me = this; + var object = {}; + if (streamName == "" || streamName == null) { + streamName = me.streamName; + } + object.streamName = streamName; + console.log("unSubscribe stream " + streamName); + me.webSocket.send("unSubscribe", object); + me.streamName = ""; + me.webRtcMediaManager.close(); + }, + + prepareRtspSession: function (rtspUri) { + var me = this; + var object = {}; + object.rtspUri = rtspUri; + console.log("prepareRtspSession " + rtspUri) + me.webSocket.send("prepareRtspSession", object); + }, + + closeMediaSession:function() { + var me = this; + me.streamName = ""; + me.webRtcMediaManager.close(); + }, + + getActiveStream: function () { + return this.streams[0]; + }, + + getAccessToAudioAndVideo: function () { + this.webRtcMediaManager.getAccessToAudioAndVideo(); + }, + + hasAccessToAudio: function () { + return this.webRtcMediaManager.isAudioMuted == -1; + }, + + hasAccessToVideo: function () { + return this.webRtcMediaManager.isVideoMuted == -1; + }, + + removeCandidatesFromSDP: function (sdp) { + var sdpArray = sdp.split("\n"); + + for (i = 0; i < sdpArray.length; i++) { + if (sdpArray[i].search("a=candidate:") != -1) { + sdpArray[i] = ""; + } + } + + //normalize sdp after modifications + var result = ""; + for (i = 0; i < sdpArray.length; i++) { + if (sdpArray[i] != "") { + result += sdpArray[i] + "\n"; + } + } + + return result; + }, + + modifyRTCP: function (sdp) { + var sdpArray = sdp.split("\n"); + var pt = "*"; + + //get pt of VP8 + for (i = 0; i < sdpArray.length; i++) { + if (sdpArray[i].search("VP8/90000") != -1) { + pt = sdpArray[i].match(/[0-9]+/)[0]; + console.log("pt is " + pt); + } + } + + //modify rtcp advert + for (i = 0; i < sdpArray.length; i++) { + if (sdpArray[i].search("a=rtcp-fb:") != -1) { + sdpArray[i] = "a=rtcp-fb:" + pt + " ccm fir\na=rtcp-fb:" + pt + " nack\na=rtcp-fb:" + pt + " nack pli"; + } + } + + //normalize sdp after modifications + var result = ""; + for (i = 0; i < sdpArray.length; i++) { + if (sdpArray[i] != "") { + result += sdpArray[i] + "\n"; + } + } + + return result; + }, + + generateId: function () { + var id = ""; + var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + for (var i = 0; i < 30; i++) { + id += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return id; + } +}; + diff --git a/client/wcs_media_client/js/ZeroClipboard.js b/client/wcs_media_client/js/ZeroClipboard.js new file mode 100644 index 00000000..c1c67431 --- /dev/null +++ b/client/wcs_media_client/js/ZeroClipboard.js @@ -0,0 +1,9 @@ +/*! +* ZeroClipboard +* The ZeroClipboard library provides an easy way to copy text to the clipboard using an invisible Adobe Flash movie and a JavaScript interface. +* Copyright (c) 2014 Jon Rohan, James M. Greene +* Licensed MIT +* http://zeroclipboard.org/ +* v2.0.0-alpha.1 +*/ +!function(){"use strict";function a(a){return a.replace(/,/g,".").replace(/[^0-9\.]/g,"")}function b(b){return parseFloat(a(b))>=10}var c,d={bridge:null,version:"0.0.0",disabled:null,outdated:null,ready:null},e={},f=0,g={},h=0,i={},j=null,k=null,l=function(){var a,b,c,d,e="ZeroClipboard.swf";if(document.currentScript&&(d=document.currentScript.src));else{var f=document.getElementsByTagName("script");if("readyState"in f[0])for(a=f.length;a--&&("interactive"!==f[a].readyState||!(d=f[a].src)););else if("loading"===document.readyState)d=f[f.length-1].src;else{for(a=f.length;a--;){if(c=f[a].src,!c){b=null;break}if(c=c.split("#")[0].split("?")[0],c=c.slice(0,c.lastIndexOf("/")+1),null==b)b=c;else if(b!==c){b=null;break}}null!==b&&(d=b)}}return d&&(d=d.split("#")[0].split("?")[0],e=d.slice(0,d.lastIndexOf("/")+1)+e),e}(),m=function(){var a=/\-([a-z])/g,b=function(a,b){return b.toUpperCase()};return function(c){return c.replace(a,b)}}(),n=function(a,b){var c,d,e;return window.getComputedStyle?c=window.getComputedStyle(a,null).getPropertyValue(b):(d=m(b),c=a.currentStyle?a.currentStyle[d]:a.style[d]),"cursor"!==b||c&&"auto"!==c||(e=a.tagName.toLowerCase(),"a"!==e)?c:"pointer"},o=function(a){a||(a=window.event);var b;this!==window?b=this:a.target?b=a.target:a.srcElement&&(b=a.srcElement),J.activate(b)},p=function(a,b,c){a&&1===a.nodeType&&(a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c))},q=function(a,b,c){a&&1===a.nodeType&&(a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c))},r=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)||a.classList.add(b),a;if(b&&"string"==typeof b){var c=(b||"").split(/\s+/);if(1===a.nodeType)if(a.className){for(var d=" "+a.className+" ",e=a.className,f=0,g=c.length;g>f;f++)d.indexOf(" "+c[f]+" ")<0&&(e+=" "+c[f]);a.className=e.replace(/^\s+|\s+$/g,"")}else a.className=b}return a},s=function(a,b){if(!a||1!==a.nodeType)return a;if(a.classList)return a.classList.contains(b)&&a.classList.remove(b),a;if(b&&"string"==typeof b||void 0===b){var c=(b||"").split(/\s+/);if(1===a.nodeType&&a.className)if(b){for(var d=(" "+a.className+" ").replace(/[\n\t]/g," "),e=0,f=c.length;f>e;e++)d=d.replace(" "+c[e]+" "," ");a.className=d.replace(/^\s+|\s+$/g,"")}else a.className=""}return a},t=function(){var a,b,c,d=1;return"function"==typeof document.body.getBoundingClientRect&&(a=document.body.getBoundingClientRect(),b=a.right-a.left,c=document.body.offsetWidth,d=Math.round(b/c*100)/100),d},u=function(a,b){var c={left:0,top:0,width:0,height:0,zIndex:A(b)-1};if(a.getBoundingClientRect){var d,e,f,g=a.getBoundingClientRect();"pageXOffset"in window&&"pageYOffset"in window?(d=window.pageXOffset,e=window.pageYOffset):(f=t(),d=Math.round(document.documentElement.scrollLeft/f),e=Math.round(document.documentElement.scrollTop/f));var h=document.documentElement.clientLeft||0,i=document.documentElement.clientTop||0;c.left=g.left+d-h,c.top=g.top+e-i,c.width="width"in g?g.width:g.right-g.left,c.height="height"in g?g.height:g.bottom-g.top}return c},v=function(a,b){var c=null==b||b&&b.cacheBust===!0&&b.useNoCache===!0;return c?(-1===a.indexOf("?")?"?":"&")+"noCache="+(new Date).getTime():""},w=function(a){var b,c,d,e=[],f=[],g=[];if(a.trustedOrigins&&("string"==typeof a.trustedOrigins?f.push(a.trustedOrigins):"object"==typeof a.trustedOrigins&&"length"in a.trustedOrigins&&(f=f.concat(a.trustedOrigins))),a.trustedDomains&&("string"==typeof a.trustedDomains?f.push(a.trustedDomains):"object"==typeof a.trustedDomains&&"length"in a.trustedDomains&&(f=f.concat(a.trustedDomains))),f.length)for(b=0,c=f.length;c>b;b++)if(f.hasOwnProperty(b)&&f[b]&&"string"==typeof f[b]){if(d=E(f[b]),C("Trusted domain: "+d,a.debug),!d)continue;if("*"===d){g=[d];break}g.push.apply(g,[d,"//"+d,window.location.protocol+"//"+d])}return g.length&&e.push("trustedOrigins="+encodeURIComponent(g.join(","))),"string"==typeof a.jsModuleId&&a.jsModuleId&&e.push("jsModuleId="+encodeURIComponent(a.jsModuleId)),e.join("&")},x=function(a,b,c){if("function"==typeof b.indexOf)return b.indexOf(a,c);var d,e=b.length;for("undefined"==typeof c?c=0:0>c&&(c=e+c),d=c;e>d;d++)if(b.hasOwnProperty(d)&&b[d]===a)return d;return-1},y=function(a){if("string"==typeof a)throw new TypeError("ZeroClipboard doesn't accept query strings.");return a.length?a:[a]},z=function(a,b,c,d){d?window.setTimeout(function(){a.apply(b,c)},0):a.apply(b,c)},A=function(a){var b,c;return a&&("number"==typeof a&&a>0?b=a:"string"==typeof a&&(c=parseInt(a,10))&&!isNaN(c)&&c>0&&(b=c)),b||("number"==typeof M.zIndex&&M.zIndex>0?b=M.zIndex:"string"==typeof M.zIndex&&(c=parseInt(M.zIndex,10))&&!isNaN(c)&&c>0&&(b=c)),b||0},B=function(a,b){if(a){var c="`"+a+"` is deprecated. See docs for more info:\n https://github.com/zeroclipboard/zeroclipboard/blob/master/docs/instructions.md#deprecations";C(c,b)}},C=function(a,b){a&&b!==!1&&"undefined"!=typeof console&&console&&(console.warn||console.log)&&(console.warn?console.warn(a):console.log(a))},D=function(){var a,b,c,d,e,f,g=arguments[0]||{};for(a=1,b=arguments.length;b>a;a++)if(null!=(c=arguments[a]))for(d in c)if(c.hasOwnProperty(d)){if(e=g[d],f=c[d],g===f)continue;void 0!==f&&(g[d]=f)}return g},E=function(a){if(null==a||""===a)return null;if(a=a.replace(/^\s+|\s+$/g,""),""===a)return null;var b=a.indexOf("//");a=-1===b?a:a.slice(b+2);var c=a.indexOf("/");return a=-1===c?a:-1===b||0===c?null:a.slice(0,c),a&&".swf"===a.slice(-4).toLowerCase()?null:a||null},F=function(){var a=function(a,b){var c,d,e;if(null!=a&&"*"!==b[0]&&("string"==typeof a&&(a=[a]),"object"==typeof a&&"length"in a))for(c=0,d=a.length;d>c;c++)if(a.hasOwnProperty(c)&&(e=E(a[c]))){if("*"===e){b.length=0,b.push("*");break}-1===x(e,b)&&b.push(e)}},b={always:"always",samedomain:"sameDomain",never:"never"};return function(c,d){var e,f=d.allowScriptAccess;if("string"==typeof f&&(e=f.toLowerCase())&&/^always|samedomain|never$/.test(e))return b[e];var g=E(d.moviePath);null===g&&(g=c);var h=[];a(d.trustedOrigins,h),a(d.trustedDomains,h);var i=h.length;if(i>0){if(1===i&&"*"===h[0])return"always";if(-1!==x(c,h))return 1===i&&c===g?"sameDomain":"always"}return"never"}}(),G=function(a){if(null==a)return[];if(Object.keys)return Object.keys(a);var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},H=function(a){if(a)for(var b in a)a.hasOwnProperty(b)&&delete a[b];return a},I=function(){var a=!1;if("boolean"==typeof d.disabled)a=d.disabled===!1;else{if("function"==typeof ActiveXObject)try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash")&&(a=!0)}catch(b){}!a&&navigator.mimeTypes["application/x-shockwave-flash"]&&(a=!0)}return a},J=function(a,b){return this instanceof J?(this.id=""+f++,g[this.id]={instance:this,elements:[],handlers:{}},a&&this.clip(a),"undefined"!=typeof b&&(B("new ZeroClipboard(elements, options)",M.debug),J.config(b)),this.options=J.config(),"boolean"!=typeof d.disabled&&(d.disabled=!I()),void(d.disabled===!1&&d.outdated!==!0&&null===d.bridge&&(d.outdated=!1,d.ready=!1,N()))):new J(a,b)};J.prototype.setText=function(a){return a&&""!==a&&(e["text/plain"]=a,d.ready===!0&&d.bridge&&d.bridge.setText(a)),this},J.prototype.setSize=function(a,b){return d.ready===!0&&d.bridge&&d.bridge.setSize(a,b),this};var K=function(a){d.ready===!0&&d.bridge&&d.bridge.setHandCursor(a)};J.prototype.destroy=function(){this.unclip(),this.off(),delete g[this.id]};var L=function(){var a,b,c,d=[],e=G(g);for(a=0,b=e.length;b>a;a++)c=g[e[a]].instance,c&&c instanceof J&&d.push(c);return d};J.version="2.0.0-alpha.1";var M={swfPath:l,trustedDomains:window.location.host?[window.location.host]:[],cacheBust:!0,forceHandCursor:!1,zIndex:999999999,debug:!1,title:null,autoActivate:!0};J.config=function(a){"object"==typeof a&&null!==a&&D(M,a);{if("string"!=typeof a||!a){var b={};for(var c in M)M.hasOwnProperty(c)&&(b[c]="object"==typeof M[c]&&null!==M[c]?"length"in M[c]?M[c].slice(0):D({},M[c]):M[c]);return b}if(M.hasOwnProperty(a))return M[a]}},J.destroy=function(){J.deactivate();for(var a in g)if(g.hasOwnProperty(a)&&g[a]){var b=g[a].instance;b&&"function"==typeof b.destroy&&b.destroy()}var c=O(d.bridge);c&&c.parentNode&&(c.parentNode.removeChild(c),d.ready=null,d.bridge=null)},J.activate=function(a){c&&(s(c,M.hoverClass),s(c,M.activeClass)),c=a,r(a,M.hoverClass),P();var b=M.title||a.getAttribute("title");if(b){var e=O(d.bridge);e&&e.setAttribute("title",b)}var f=M.forceHandCursor===!0||"pointer"===n(a,"cursor");K(f)},J.deactivate=function(){var a=O(d.bridge);a&&(a.style.left="0px",a.style.top="-9999px",a.removeAttribute("title")),c&&(s(c,M.hoverClass),s(c,M.activeClass),c=null)};var N=function(){var a,b,c=document.getElementById("global-zeroclipboard-html-bridge");if(!c){var e=J.config();e.jsModuleId="string"==typeof j&&j||"string"==typeof k&&k||null;var f=F(window.location.host,M),g=w(e),h=M.moviePath+v(M.moviePath,M),i=' ';c=document.createElement("div"),c.id="global-zeroclipboard-html-bridge",c.setAttribute("class","global-zeroclipboard-container"),c.style.position="absolute",c.style.left="0px",c.style.top="-9999px",c.style.width="15px",c.style.height="15px",c.style.zIndex=""+A(M.zIndex),document.body.appendChild(c),c.innerHTML=i}a=document["global-zeroclipboard-flash-bridge"],a&&(b=a.length)&&(a=a[b-1]),d.bridge=a||c.children[0].lastElementChild},O=function(a){for(var b=/^OBJECT|EMBED$/,c=a&&a.parentNode;c&&b.test(c.nodeName)&&c.parentNode;)c=c.parentNode;return c||null},P=function(){if(c){var a=u(c,M.zIndex),b=O(d.bridge);b&&(b.style.top=a.top+"px",b.style.left=a.left+"px",b.style.width=a.width+"px",b.style.height=a.height+"px",b.style.zIndex=a.zIndex+1),d.ready===!0&&d.bridge&&d.bridge.setSize(a.width,a.height)}return this};J.prototype.on=function(a,b){var c,e,f,h={},i=g[this.id]&&g[this.id].handlers;if("string"==typeof a&&a)f=a.toLowerCase().split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)a.hasOwnProperty(c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.on(c,a[c]);if(f&&f.length){for(c=0,e=f.length;e>c;c++)a=f[c].replace(/^on/,""),h[a]=!0,i[a]||(i[a]=[]),i[a].push(b);h.noflash&&d.disabled&&S.call(this,"noflash",{}),h.wrongflash&&d.outdated&&S.call(this,"wrongflash",{flashVersion:d.version}),h.load&&d.ready&&S.call(this,"load",{flashVersion:d.version})}return this},J.prototype.off=function(a,b){var c,d,e,f,h,i=g[this.id]&&g[this.id].handlers;if(0===arguments.length)f=G(i);else if("string"==typeof a&&a)f=a.split(/\s+/);else if("object"==typeof a&&a&&"undefined"==typeof b)for(c in a)a.hasOwnProperty(c)&&"string"==typeof c&&c&&"function"==typeof a[c]&&this.off(c,a[c]);if(f&&f.length)for(c=0,d=f.length;d>c;c++)if(a=f[c].toLowerCase().replace(/^on/,""),h=i[a],h&&h.length)if(b)for(e=x(b,h);-1!==e;)h.splice(e,1),e=x(b,h,e);else i[a].length=0;return this},J.prototype.handlers=function(a){var b,c=null,d=g[this.id]&&g[this.id].handlers;if(d){if("string"==typeof a&&a)return d[a]?d[a].slice(0):null;c={};for(b in d)d.hasOwnProperty(b)&&d[b]&&(c[b]=d[b].slice(0))}return c};var Q=function(a,b,c,d){var e=g[this.id]&&g[this.id].handlers[a];if(e&&e.length){var f,h,i,j=b||this;for(f=0,h=e.length;h>f;f++)i=e[f],b=j,"string"==typeof i&&"function"==typeof window[i]&&(i=window[i]),"object"==typeof i&&i&&"function"==typeof i.handleEvent&&(b=i,i=i.handleEvent),"function"==typeof i&&z(i,b,c,d)}return this};J.prototype.clip=function(a){a=y(a);for(var b=0;bd;d++)f=g[c[d]].instance,f&&f instanceof J&&h.push(f);return h};M.hoverClass="zeroclipboard-is-hover",M.activeClass="zeroclipboard-is-active",M.trustedOrigins=null,M.allowScriptAccess=null,M.useNoCache=!0,M.moviePath="ZeroClipboard.swf",J.detectFlashSupport=function(){return B("ZeroClipboard.detectFlashSupport",M.debug),I()},J.dispatch=function(a,b){if("string"==typeof a&&a){var d=a.toLowerCase().replace(/^on/,"");if(d)for(var e=c?R(c):L(),f=0,g=e.length;g>f;f++)S.call(e[f],d,b)}},J.prototype.setHandCursor=function(a){return B("ZeroClipboard.prototype.setHandCursor",M.debug),a="boolean"==typeof a?a:!!a,K(a),M.forceHandCursor=a,this},J.prototype.reposition=function(){return B("ZeroClipboard.prototype.reposition",M.debug),P()},J.prototype.receiveEvent=function(a,b){if(B("ZeroClipboard.prototype.receiveEvent",M.debug),"string"==typeof a&&a){var c=a.toLowerCase().replace(/^on/,"");c&&S.call(this,c,b)}},J.prototype.setCurrent=function(a){return B("ZeroClipboard.prototype.setCurrent",M.debug),J.activate(a),this},J.prototype.resetBridge=function(){return B("ZeroClipboard.prototype.resetBridge",M.debug),J.deactivate(),this},J.prototype.setTitle=function(a){if(B("ZeroClipboard.prototype.setTitle",M.debug),a=a||M.title||c&&c.getAttribute("title")){var b=O(d.bridge);b&&b.setAttribute("title",a)}return this},J.setDefaults=function(a){B("ZeroClipboard.setDefaults",M.debug),J.config(a)},J.prototype.addEventListener=function(a,b){return B("ZeroClipboard.prototype.addEventListener",M.debug),this.on(a,b)},J.prototype.removeEventListener=function(a,b){return B("ZeroClipboard.prototype.removeEventListener",M.debug),this.off(a,b)},J.prototype.ready=function(){return B("ZeroClipboard.prototype.ready",M.debug),d.ready===!0};var S=function(f,g){f=f.toLowerCase().replace(/^on/,"");var h=g&&g.flashVersion&&a(g.flashVersion)||null,i=c,j=!0;switch(f){case"load":if(h){if(!b(h))return void S.call(this,"onWrongFlash",{flashVersion:h});d.outdated=!1,d.ready=!0,d.version=h}break;case"wrongflash":h&&!b(h)&&(d.outdated=!0,d.ready=!1,d.version=h);break;case"mouseover":r(i,M.hoverClass);break;case"mouseout":M.autoActivate===!0&&J.deactivate();break;case"mousedown":r(i,M.activeClass);break;case"mouseup":s(i,M.activeClass);break;case"datarequested":var k=i.getAttribute("data-clipboard-target"),l=k?document.getElementById(k):null;if(l){var m=l.value||l.textContent||l.innerText;m&&this.setText(m)}else{var n=i.getAttribute("data-clipboard-text");n&&this.setText(n)}j=!1;break;case"complete":H(e)}var o=i,p=[this,g];return Q.call(this,f,o,p,j)};"function"==typeof define&&define.amd?define(["require","exports","module"],function(a,b,c){return j=c&&c.id||null,J}):"object"==typeof module&&module&&"object"==typeof module.exports&&module.exports?(k=module.id||null,module.exports=J):window.ZeroClipboard=J}(); \ No newline at end of file diff --git a/client/wcs_media_client/js/ZeroClipboard.swf b/client/wcs_media_client/js/ZeroClipboard.swf new file mode 100644 index 00000000..a16e8ed1 Binary files /dev/null and b/client/wcs_media_client/js/ZeroClipboard.swf differ diff --git a/client/wcs_media_client/js/jquery/jquery-1.11.0.js b/client/wcs_media_client/js/jquery/jquery-1.11.0.js new file mode 100644 index 00000000..3c88fa8b --- /dev/null +++ b/client/wcs_media_client/js/jquery/jquery-1.11.0.js @@ -0,0 +1,10337 @@ +/*! + * jQuery JavaScript Library v1.11.0 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-01-23T21:02Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +// + +var deletedIds = []; + +var slice = deletedIds.slice; + +var concat = deletedIds.concat; + +var push = deletedIds.push; + +var indexOf = deletedIds.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var trim = "".trim; + +var support = {}; + + + +var + version = "1.11.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return a 'clean' array + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return just the object + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: deletedIds.sort, + splice: deletedIds.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + /* jshint eqeqeq: false */ + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + return obj - parseFloat( obj ) >= 0; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + isPlainObject: function( obj ) { + var key; + + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call(obj, "constructor") && + !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Support: IE<9 + // Handle iteration over inherited properties before own properties. + if ( support.ownLast ) { + for ( key in obj ) { + return hasOwn.call( obj, key ); + } + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: trim && !trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( indexOf ) { + return indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + while ( j < len ) { + first[ i++ ] = second[ j++ ]; + } + + // Support: IE<9 + // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) + if ( len !== len ) { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: function() { + return +( new Date() ); + }, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v1.10.16 + * http://sizzlejs.com/ + * + * Copyright 2013 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-01-13 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + compile, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( documentIsHTML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== strundefined && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, + doc = node ? node.ownerDocument || node : preferredDoc, + parent = doc.defaultView; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsHTML = !isXML( doc ); + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", function() { + setDocument(); + }, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", function() { + setDocument(); + }); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if getElementsByClassName can be trusted + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) { + div.innerHTML = "
    "; + + // Support: Safari<4 + // Catch class over-caching + div.firstChild.className = "i"; + // Support: Opera<10 + // Catch gEBCN failure to find non-leading classes + return div.getElementsByClassName("i").length === 2; + }); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // Support: IE8, Opera 10-12 + // Nothing should be selected when empty strings follow ^= or $= or *= + if ( div.querySelectorAll("[t^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] && match[4] !== undefined ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + } + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +} + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome<14 +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + ret = [], + self = this, + len = self.length; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + ret = jQuery.unique( ret ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + } + + return this.pushStack( ret ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + + } else if ( !(--remaining) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + } +}); + +/** + * Clean-up method for dom ready events + */ +function detach() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } +} + +/** + * The ready event handler and self cleanup method + */ +function completed() { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + + +var strundefined = typeof undefined; + + + +// Support: IE<9 +// Iteration over object's inherited properties before its own +var i; +for ( i in jQuery( support ) ) { + break; +} +support.ownLast = i !== "0"; + +// Note: most support tests are defined in their respective modules. +// false until the test is run +support.inlineBlockNeedsLayout = false; + +jQuery(function() { + // We need to execute this one support test ASAP because we need to know + // if body.style.zoom needs to be set. + + var container, div, + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + // Setup + container = document.createElement( "div" ); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + div = document.createElement( "div" ); + body.appendChild( container ).appendChild( div ); + + if ( typeof div.style.zoom !== strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.style.cssText = "border:0;margin:0;width:1px;padding:1px;display:inline;zoom:1"; + + if ( (support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 )) ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = null; +}); + + + + +(function() { + var div = document.createElement( "div" ); + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( elem ) { + var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ], + nodeType = +elem.nodeType || 1; + + // Do not set data on non-element DOM nodes because it will not be cleared (#8335). + return nodeType !== 1 && nodeType !== 9 ? + false : + + // Nodes accept data unless otherwise specified; rejection can be conditional + !noData || noData !== true && elem.getAttribute("classid") === noData; +}; + + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} + +function internalData( elem, name, data, pvt /* Internal Use Only */ ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var ret, thisCache, + internalKey = jQuery.expando, + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + // Avoid exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( typeof name === "string" ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, i, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + i = name.length; + while ( i-- ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + /* jshint eqeqeq: false */ + } else if ( support.deleteExpando || cache != cache.window ) { + /* jshint eqeqeq: true */ + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // The following elements (space-suffixed to avoid Object.prototype collisions) + // throw uncatchable exceptions if you attempt to set expando properties + noData: { + "applet ": true, + "embed ": true, + // ...but Flash objects (which have this classid) *can* handle expandos + "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[0], + attrs = elem && elem.attributes; + + // Special expections of .data basically thwart jQuery.access, + // so implement the relevant behavior ourselves + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + name = attrs[i].name; + + if ( name.indexOf("data-") === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return arguments.length > 1 ? + + // Sets one value + this.each(function() { + jQuery.data( this, key, value ); + }) : + + // Gets one value + // Try to fetch any internally stored data first + elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; +}; +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + var fragment = document.createDocumentFragment(), + div = document.createElement("div"), + input = document.createElement("input"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
    a"; + + // IE strips leading whitespace when .innerHTML is used + support.leadingWhitespace = div.firstChild.nodeType === 3; + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + support.tbody = !div.getElementsByTagName( "tbody" ).length; + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + support.html5Clone = + document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + input.type = "checkbox"; + input.checked = true; + fragment.appendChild( input ); + support.appendChecked = input.checked; + + // Make sure textarea (and checkbox) defaultValue is properly cloned + // Support: IE6-IE11+ + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // #11217 - WebKit loses check when the name is after the checked attribute + fragment.appendChild( div ); + div.innerHTML = ""; + + // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 + // old WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + support.noCloneEvent = true; + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Execute the test only if not already executed in another module. + if (support.deleteExpando == null) { + // Support: IE<9 + support.deleteExpando = true; + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + } + + // Null elements to avoid leaks in IE. + fragment = div = input = null; +})(); + + +(function() { + var i, eventName, + div = document.createElement( "div" ); + + // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event) + for ( i in { submit: true, change: true, focusin: true }) { + eventName = "on" + i; + + if ( !(support[ i + "Bubbles" ] = eventName in window) ) { + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) + div.setAttribute( eventName, "t" ); + support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false; + } + } + + // Null elements to avoid leaks in IE. + div = null; +})(); + + +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + /* jshint eqeqeq: false */ + for ( ; cur != this; cur = cur.parentNode || this ) { + /* jshint eqeqeq: true */ + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && ( + // Support: IE < 9 + src.returnValue === false || + // Support: Android < 4.0 + src.getPreventDefault && src.getPreventDefault() ) ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = jQuery._data( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + jQuery._removeData( doc, fix ); + } else { + jQuery._data( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
    ", "
    " ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + col: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
    ", "
    " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +// Support: IE<8 +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!support.noCloneEvent || !support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
    " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + deletedIds.push( id ); + } + } + } + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[i], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle ? + + // Use of this method is a temporary fix (more like optmization) until something better comes along, + // since it was removed from specification and supported only in FF + window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "