<author email="dev@cordova.apache.org" href="http://cordova.io">
Apache Cordova Team
</author>
- <preference name="AutoHideSplashScreen" value="true"/>
- <preference name="SplashScreenDelay" value="0"/>
+ <preference name="AutoHideSplashScreen" value="true" />
+ <preference name="SplashScreenDelay" value="0" />
<preference name="SplashShowOnlyFirstTime" value="true" />
-
<content src="index.html" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
-
<allow-navigation href="http://*/*" />
<allow-navigation href="https://*/*" />
<allow-navigation href="data:*" />
<access origin="http://ip*" />
-
<preference name="ErrorUrl" value="error.html" />
<preference name="Orientation" value="portrait" />
<preference name="UseSwiftLanguageVersion" value="4.0" />
<preference name="DisallowOverscroll" value="true" />
<preference name="UIWebViewBounce" value="false" />
- <preference name="BackupWebStorage" value="local"/>
-
+ <preference name="BackupWebStorage" value="local" />
<platform name="android">
<allow-intent href="market:*" />
</platform>
<feature name="TouchID">
<param name="ios-package" value="TouchID" />
</feature>
+ <edit-config file="*-Info.plist" mode="merge" target="NSCameraUsageDescription">
+ <string>APP需要使用您的相机权限,没有该权限将无法完成扫一扫功能</string>
+ </edit-config>
<plugin name="cordova-plugin-fingerprint-aio" spec="~1.7.0">
<variable name="FACEID_USAGE_DESCRIPTION" value="认证中..." />
</plugin>
<plugin name="cordova-plugin-touch-id" spec="~3.3.1">
<variable name="FACEID_USAGE_DESCRIPTION" value=" " />
</plugin>
- <plugin name="cordova-plugin-whitelist" spec="1" />
+ <plugin name="cordova-plugin-whitelist" spec="^1.3.3" />
<plugin name="cordova-plugin-advanced-http" spec="~2.1.1">
<variable name="OKHTTP_VERSION" value="3.10.0" />
</plugin>
-
- <plugin name="cordova-plugin-statusbar" spec="~2.4.2" />
- <edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
- <string>APP需要使用您的相机权限,没有该权限将无法完成扫一扫功能</string>
- </edit-config>
+ <plugin name="cordova-plugin-statusbar" spec="^2.4.2" />
+ <plugin name="cordova-plugin-disable-ios11-statusbar" spec="~1.0.0" />
+ <plugin name="cordova-plugin-qrscanner" spec="^3.0.1" />
+ <plugin name="cordova-plugin-camera" spec="~4.0.3" />
+ <plugin name="cordova-plugin-inappbrowser" spec="~3.0.0" />
+ <plugin name="cordova-plugin-device" spec="~2.0.2" />
+ <plugin name="cordova-plugin-themeablebrowser" spec="~0.2.17" />
</widget>
"resolved": "https://registry.npmjs.org/cordova-plugin-inappbrowser/-/cordova-plugin-inappbrowser-3.0.0.tgz",
"integrity": "sha1-1K4A02Z2IQdRBXrSWK5K1KkWGto="
},
+ "cordova-plugin-jcore": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/cordova-plugin-jcore/-/cordova-plugin-jcore-1.3.0.tgz",
+ "integrity": "sha512-QmkdABlkIHFaMUBsrjPqhpaWS7wuboRPeeVEUNoc4FlZNRoQgw35v0MaW+SbOk4SzVsEGvN6IFSVqa4106ljUw=="
+ },
"cordova-plugin-qrscanner": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/cordova-plugin-qrscanner/-/cordova-plugin-qrscanner-3.0.1.tgz",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
+ "jpush-phonegap-plugin": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/jpush-phonegap-plugin/-/jpush-phonegap-plugin-3.7.2.tgz",
+ "integrity": "sha512-q5gGu0m1uf6Mf1puFd9o1hp32rok+/GgR39ZDGWdYULc6KX5zy932wdzLDlTYpjBW9Gec/HZmj1HTbQIMvppiA=="
+ },
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"cordova-plugin-file": "^6.0.1",
"cordova-plugin-fingerprint-aio": "^1.7.0",
"cordova-plugin-inappbrowser": "^3.0.0",
+ "cordova-plugin-jcore": "^1.3.0",
"cordova-plugin-qrscanner": "^3.0.1",
"cordova-plugin-statusbar": "^2.4.2",
"cordova-plugin-themeablebrowser": "^0.2.18",
- "cordova-plugin-touch-id": "^3.4.0"
+ "cordova-plugin-touch-id": "^3.4.0",
+ "jpush-phonegap-plugin": "^3.7.2"
},
"cordova": {
"plugins": {
"cordova-plugin-camera": {},
"cordova-plugin-inappbrowser": {},
"cordova-plugin-device": {},
- "cordova-plugin-themeablebrowser": {}
+ "cordova-plugin-themeablebrowser": {},
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "bd22b85f247a6e2ca307d3c5",
+ "CHANNEL": "developer-default"
+ }
},
"platforms": [
"android",
{
"xml": "<feature name=\"ThemeableBrowser\"><param name=\"android-package\" value=\"com.initialxy.cordova.themeablebrowser.ThemeableBrowser\" /></feature>",
"count": 1
+ },
+ {
+ "xml": "<feature name=\"JPushPlugin\"><param name=\"android-package\" value=\"cn.jiguang.cordova.push.JPushPlugin\" /></feature>",
+ "count": 1
}
]
}
"/manifest": [
{
"xml": "<uses-permission android:name=\"android.permission.INTERNET\" />",
+ "count": 2
+ },
+ {
+ "xml": "<permission android:name=\"com.supwisdom.dlapp.permission.JPUSH_MESSAGE\" android:protectionLevel=\"signature\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"com.supwisdom.dlapp.permission.JPUSH_MESSAGE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.RECEIVE_USER_PRESENT\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.VIBRATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.ACCESS_LOCATION_EXTRA_COMMANDS\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\" />",
+ "count": 1
+ },
+ {
+ "xml": "<uses-permission android:name=\"android.permission.GET_TASKS\" />",
"count": 1
}
],
"xml": "<provider android:authorities=\"${applicationId}.provider\" android:exported=\"false\" android:grantUriPermissions=\"true\" android:name=\"org.apache.cordova.camera.FileProvider\"><meta-data android:name=\"android.support.FILE_PROVIDER_PATHS\" android:resource=\"@xml/camera_provider_paths\" /></provider>",
"count": 1
}
+ ],
+ "/manifest/application": [
+ {
+ "xml": "<activity android:exported=\"false\" android:name=\"cn.jpush.android.ui.PopWinActivity\" android:theme=\"@style/MyDialogStyle\"></activity>",
+ "count": 1
+ },
+ {
+ "xml": "<activity android:configChanges=\"orientation|keyboardHidden\" android:exported=\"false\" android:name=\"cn.jpush.android.ui.PushActivity\" android:theme=\"@android:style/Theme.NoTitleBar\"><intent-filter><action android:name=\"cn.jpush.android.ui.PushActivity\" /><category android:name=\"android.intent.category.DEFAULT\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter></activity>",
+ "count": 1
+ },
+ {
+ "xml": "<service android:exported=\"false\" android:name=\"cn.jpush.android.service.PushService\" android:process=\":pushcore\"><intent-filter><action android:name=\"cn.jpush.android.intent.REGISTER\" /><action android:name=\"cn.jpush.android.intent.REPORT\" /><action android:name=\"cn.jpush.android.intent.PushService\" /><action android:name=\"cn.jpush.android.intent.PUSH_TIME\" /></intent-filter></service>",
+ "count": 1
+ },
+ {
+ "xml": "<provider android:authorities=\"com.supwisdom.dlapp.DataProvider\" android:exported=\"false\" android:name=\"cn.jpush.android.service.DataProvider\" android:process=\":pushcore\" />",
+ "count": 1
+ },
+ {
+ "xml": "<service android:enabled=\"true\" android:exported=\"true\" android:name=\"cn.jpush.android.service.DaemonService\"><intent-filter><action android:name=\"cn.jpush.android.intent.DaemonService\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter></service>",
+ "count": 1
+ },
+ {
+ "xml": "<provider android:authorities=\"com.supwisdom.dlapp.DownloadProvider\" android:exported=\"true\" android:name=\"cn.jpush.android.service.DownloadProvider\" />",
+ "count": 1
+ },
+ {
+ "xml": "<receiver android:enabled=\"true\" android:exported=\"false\" android:name=\"cn.jpush.android.service.PushReceiver\"><intent-filter android:priority=\"1000\"><action android:name=\"cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter><intent-filter><action android:name=\"android.intent.action.USER_PRESENT\" /><action android:name=\"android.net.conn.CONNECTIVITY_CHANGE\" /></intent-filter><intent-filter><action android:name=\"android.intent.action.PACKAGE_ADDED\" /><action android:name=\"android.intent.action.PACKAGE_REMOVED\" /><data android:scheme=\"package\" /></intent-filter></receiver>",
+ "count": 1
+ },
+ {
+ "xml": "<receiver android:exported=\"false\" android:name=\"cn.jpush.android.service.AlarmReceiver\" />",
+ "count": 1
+ },
+ {
+ "xml": "<receiver android:name=\"cn.jiguang.cordova.push.JPushEventReceiver\"><intent-filter><action android:name=\"cn.jpush.android.intent.RECEIVE_MESSAGE\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter></receiver>",
+ "count": 1
+ },
+ {
+ "xml": "<activity android:exported=\"true\" android:name=\"cn.jpush.android.service.JNotifyActivity\" android:taskAffinity=\"jpush.custom\" android:theme=\"@android:style/Theme.Translucent.NoTitleBar\"><intent-filter><action android:name=\"cn.jpush.android.intent.JNotifyActivity\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter></activity>",
+ "count": 1
+ },
+ {
+ "xml": "<service android:name=\"cn.jiguang.cordova.push.PushService\" android:process=\":pushcore\"><intent-filter><action android:name=\"cn.jiguang.user.service.action\" /></intent-filter></service>",
+ "count": 1
+ },
+ {
+ "xml": "<receiver android:enabled=\"true\" android:exported=\"false\" android:name=\"cn.jiguang.cordova.push.JPushReceiver\"><intent-filter><action android:name=\"cn.jpush.android.intent.REGISTRATION\" /><action android:name=\"cn.jpush.android.intent.MESSAGE_RECEIVED\" /><action android:name=\"cn.jpush.android.intent.NOTIFICATION_RECEIVED\" /><action android:name=\"cn.jpush.android.intent.NOTIFICATION_OPENED\" /><action android:name=\"cn.jpush.android.intent.CONNECTION\" /><category android:name=\"com.supwisdom.dlapp\" /></intent-filter></receiver>",
+ "count": 1
+ },
+ {
+ "xml": "<meta-data android:name=\"JPUSH_CHANNEL\" android:value=\"developer-default\" />",
+ "count": 1
+ },
+ {
+ "xml": "<meta-data android:name=\"JPUSH_APPKEY\" android:value=\"your_jpush_appkey\" />",
+ "count": 1
+ }
]
}
},
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
},
"dependent_plugins": {},
"clobbers": [
"cordova.ThemeableBrowser"
]
+ },
+ {
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
],
"plugin_metadata": {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
}
}
<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="10000" android:versionName="1.0.0" package="com.supwisdom.dlapp" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
- <uses-permission android:name="android.permission.INTERNET" />
<application android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher" android:label="@string/launcher_name" android:supportsRtl="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTop" android:name="MainActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/launcher_name">
<provider android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true" android:name="org.apache.cordova.camera.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_provider_paths" />
</provider>
+ <activity android:exported="false" android:name="cn.jpush.android.ui.PopWinActivity" android:theme="@style/MyDialogStyle" />
+ <activity android:configChanges="orientation|keyboardHidden" android:exported="false" android:name="cn.jpush.android.ui.PushActivity" android:theme="@android:style/Theme.NoTitleBar">
+ <intent-filter>
+ <action android:name="cn.jpush.android.ui.PushActivity" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ </activity>
+ <service android:exported="false" android:name="cn.jpush.android.service.PushService" android:process=":pushcore">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.REGISTER" />
+ <action android:name="cn.jpush.android.intent.REPORT" />
+ <action android:name="cn.jpush.android.intent.PushService" />
+ <action android:name="cn.jpush.android.intent.PUSH_TIME" />
+ </intent-filter>
+ </service>
+ <provider android:authorities="com.supwisdom.dlapp.DataProvider" android:exported="false" android:name="cn.jpush.android.service.DataProvider" android:process=":pushcore" />
+ <service android:enabled="true" android:exported="true" android:name="cn.jpush.android.service.DaemonService">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.DaemonService" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ </service>
+ <provider android:authorities="com.supwisdom.dlapp.DownloadProvider" android:exported="true" android:name="cn.jpush.android.service.DownloadProvider" />
+ <receiver android:enabled="true" android:exported="false" android:name="cn.jpush.android.service.PushReceiver">
+ <intent-filter android:priority="1000">
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.USER_PRESENT" />
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_ADDED" />
+ <action android:name="android.intent.action.PACKAGE_REMOVED" />
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+ <receiver android:exported="false" android:name="cn.jpush.android.service.AlarmReceiver" />
+ <receiver android:name="cn.jiguang.cordova.push.JPushEventReceiver">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ </receiver>
+ <activity android:exported="true" android:name="cn.jpush.android.service.JNotifyActivity" android:taskAffinity="jpush.custom" android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.JNotifyActivity" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ </activity>
+ <service android:name="cn.jiguang.cordova.push.PushService" android:process=":pushcore">
+ <intent-filter>
+ <action android:name="cn.jiguang.user.service.action" />
+ </intent-filter>
+ </service>
+ <receiver android:enabled="true" android:exported="false" android:name="cn.jiguang.cordova.push.JPushReceiver">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.REGISTRATION" />
+ <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" />
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" />
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" />
+ <action android:name="cn.jpush.android.intent.CONNECTION" />
+ <category android:name="com.supwisdom.dlapp" />
+ </intent-filter>
+ </receiver>
+ <meta-data android:name="JPUSH_CHANNEL" android:value="developer-default" />
+ <meta-data android:name="JPUSH_APPKEY" android:value="your_jpush_appkey" />
</application>
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.CAMERA" android:required="false" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <permission android:name="com.supwisdom.dlapp.permission.JPUSH_MESSAGE" android:protectionLevel="signature" />
+ <uses-permission android:name="com.supwisdom.dlapp.permission.JPUSH_MESSAGE" />
+ <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.GET_TASKS" />
</manifest>
</div>
</div>
<div class="weui-cell" style="padding:0 10px; ">
- <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">银行卡号</label></div>
+ <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">证件类型</label></div>
<div class="weui-cell__bd">
- <input class="weui-input" type="text" id="cardnum" style="font-size: 14px;" placeholder="市民卡对应的银行卡号">
+ <input class="weui-input" type="text" id='idtype' placeholder="请选择证件类型" style="font-size: 14px;" />
</div>
</div>
- </div>
-
- <div class="weui-cells__title">短信验证市民卡预留的手机号</div>
- <div class="weui-cells weui-cells_form">
<div class="weui-cell" style="padding:0 10px; ">
- <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">手机号</label></div>
+ <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">证件号</label></div>
<div class="weui-cell__bd">
- <input class="weui-input" type="tel" id="phone" style="font-size: 14px;" placeholder="请输入市民卡预留的手机号" disabled="disabled" >
+ <input class="weui-input" type="text" id="idno" style="font-size: 14px;" placeholder="请输入您的证件号" >
</div>
</div>
- <div class="weui-cell weui-cell_vcode" style="padding:0 10px; ">
- <div class="weui-cell__hd">
- <label class="weui-label" style="width: 80px;font-size: 14px;">验证码</label>
- </div>
+ <div class="weui-cell" style="padding:0 10px; ">
+ <div class="weui-cell__hd"><label class="weui-label" style="width: 80px;font-size: 14px;">银行卡号</label></div>
<div class="weui-cell__bd">
- <input class="weui-input" type="number" id="code" style="font-size: 14px;" placeholder="请输入验证码" maxlength="6">
- </div>
- <div class="weui-cell__ft">
- <button class="weui-vcode-btn" onclick="app.getCode()" id="codebtn" style="width: 100px;height: 1rem;font-size: 14px;">获取验证码</button>
+ <input class="weui-input" type="text" id="cardnum" style="font-size: 14px;" placeholder="市民卡对应的银行卡号">
</div>
</div>
</div>
-
<section class="aui-content-padded" style="margin-top: 30px;">
<div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.doNext()">下一步</div>
</section>
"clobbers": [
"cordova.ThemeableBrowser"
]
+ },
+ {
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
];
module.exports.metadata = {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
};
});
\ No newline at end of file
V1Bills(param,function(ok,ret){
if(ok){
if(ret.code==200){
+ $.hideLoading();
if(ret.page&&ret.page.count>0){
app.initBillView(ret.page)
}else{
+var dict;
var app = {
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
-
+
onDeviceReady: function() {
var uid = window.localStorage.getItem("uid");
- var phone = window.localStorage.getItem("phoneX");
- if(!isEmpty(phone)){
- $("#phone").val(phone)
- }else{
- phone = window.localStorage.getItem("phone");
- $("#phone").val(phone)
- }
+ this.loadData();
+ },
+ loadData: function() {
+ $.showLoading("正在加载");
+ V1Idtypes(function(ok, ret) {
+ if (ok) {
+ $.hideLoading();
+ if (ret.code == 200) {
+ dict = ret.idtypes;
+ let keys = Object.keys(dict);
+ let vals = Object.values(dict);
+ console.log(keys, vals)
+ var items=[];
+ for(var key of keys){
+ var bean = {
+ "title":dict[key],
+ "value":key
+ }
+ items.push(bean)
+ }
+ $("#idtype").val(items[0].title)
+ $("#idtype").attr("data-values",items[0].value)
+ $("#idtype").select({
+ title: "请选择证件类型",
+ items: items
+ });
+ } else {
+ $.alert(ret.msg, "错误");
+ }
+ } else {
+ $.hideLoading();
+ $.alert("请求失败了 " + ret.status + ",请稍后再试", "错误");
+ }
+ })
},
doNext: function() {
- var code = $("#code").val();
- var cardnum = $("#cardnum").val();
- var name = $("#name").val();
- if(isEmpty(name)||isEmpty(code)||isEmpty(cardnum)){
+ var cardnum = $("#cardnum").val();
+ var name = $("#name").val();
+ var idno = $("#idno").val();
+ if (isEmpty(name) || isEmpty(cardnum)||isEmpty(idno)) {
+ return;
+ }
+ var idtype = $("#idtype").attr("data-values")
+ if(isEmpty(idtype)){
+ $.alert("请选择证件类型", "错误");
return;
}
/*var agree = $("input[type=checkbox]:checked").val();
return;
}*/
$.showLoading("正在处理");
- var param={
- "cardno":cardnum,
- "code":code,
- "name":name
+ var param = {
+ "cardno": cardnum,
+ "idtype": idtype,
+ "name": name,
+ "idno": idno
}
- V1Bindcard(param,function(ok,ret){
- if(ok){
+ V1Bindcard(param, function(ok, ret) {
+ if (ok) {
$.hideLoading();
console.log(ret)
- if(ret.code==200){
- window.localStorage.setItem("paypwdtype","new");
- window.localStorage.setItem("userid",ret.userid);
- window.localStorage.setItem("signed",ret.signed);
- window.localStorage.setItem("name",name);
- window.localStorage.setItem("paypwdset",ret.paypwdset);
- if(ret.paypwdset){
- if(!isEmpty(ret.signed)&&signed=='yes'){
- window.location='main.html'
- }else{
- window.location='signxy.html'
- }
- }else{
- window.location="paypwdset.html";
- }
- }else{
- if(ret.code==-1){
- $.alert(ret.msg, "提示",function(){
- window.location="main.html"
+ if (ret.code == 200) {
+ window.localStorage.setItem("phoneX",ret.phonex);
+ window.localStorage.setItem("name", name);
+ window.localStorage.setItem("personid", ret.personid);
+ window.localStorage.setItem("signed", ret.signed);
+ window.localStorage.setItem("paypwdset", ret.paypwdset);
+ window.location = "bindcheck.html";
+ } else {
+ if (ret.code == -1) {
+ $.alert(ret.msg, "提示", function() {
+ window.location = "main.html"
});
- }else{
- $.alert(ret.msg, "错误");
+ } else {
+ $.alert(ret.msg, "错误");
}
- }
- }else{
- $.hideLoading();
- $.alert("请求失败了 "+ret.status+",请稍后再试", "错误");
- }
- })
- },
- getCode :function(){
- $.showLoading("请求中");
- V1Code(function(ok,ret){
- if(ok){
- $.hideLoading();
- if(ret.code==200){
- $("#codebtn").attr("disabled","disabled")
- $("#codebtn").addClass("vcodedisabled")
- btnTime('codebtn');
- }else{
- $.alert(ret.msg, "错误");
- }
- }else{
+ }
+ } else {
$.hideLoading();
- $.alert("请求失败了"+ret.status+",请稍后再试", "错误");
+ $.alert("请求失败了 " + ret.status + ",请稍后再试", "错误");
}
})
}
};
-app.initialize();
+app.initialize();
\ No newline at end of file
if(ret.now-t>1000*60*10){
window.location = "login.html";
}else{
-
window.location = "main.html";
}
+ }else{
+ window.location = "login.html";
}
} else {
//alert('无法请求到服务器,请检查网络并稍后再试');
window.location = "findpwd.html";
},
login: function(){
- window.location = "main.html";
//loading("正在处理");
var phone = $("#phone").val()
var pwd = $("#pwd").val()
onDeviceReady: function() {
var uid = window.localStorage.getItem("token");
- var qrcode = new QRCode(document.getElementById("qrcode"), {
- text: uid,
- width: 150,
- height: 150,
- colorDark : "#000000",
- colorLight : "#ffffff",
- correctLevel : QRCode.CorrectLevel.L
- });
+ this.loadQrcode();
+ setInterval(function () {
+ window.location.reload();
+ },100000);
},
- toBillDetail :function(refno){
-
+ loadQrcode: function() {
+ $.showLoading("加载中");
+ V1Qrcode(function(ok, ret) {
+ if (ok) {
+ console.log(ret)
+ if (ret.code == 200) {
+ $.hideLoading();
+ var qrcode = new QRCode(document.getElementById("qrcode"), {
+ text: ret.qrcode,
+ width: 150,
+ height: 150,
+ colorDark: "#000000",
+ colorLight: "#ffffff",
+ correctLevel: QRCode.CorrectLevel.L
+ });
+ } else {
+ $.hideLoading();
+ $.alert("请求失败,请稍后再试", "错误");
+ }
+ } else {
+ $.hideLoading();
+ $.alert("请求失败了:" + ret.status + "请稍后再试", "错误");
+ }
+ })
+ },
+ refresh:function(){
+ V1Qrcode(function(ok, ret) {
+ if (ok) {
+ if (ret.code == 200) {
+ $.hideLoading();
+ var qrcode = new QRCode(document.getElementById("qrcode"), {
+ text: ret.qrcode,
+ width: 150,
+ height: 150,
+ colorDark: "#000000",
+ colorLight: "#ffffff",
+ correctLevel: QRCode.CorrectLevel.L
+ });
+ } else {
+ $.hideLoading();
+ $.alert("请求失败,请稍后再试", "错误");
+ }
+ } else {
+ $.hideLoading();
+ $.alert("请求失败了:" + ret.status + "请稍后再试", "错误");
+ }
+ })
}
};
app.initialize();
\ No newline at end of file
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
-
onDeviceReady: function() {
- var uid = window.localStorage.getItem("uid");
- var phone = window.localStorage.getItem("phoneX");
-
},
editPwd: function() {
window.location = "editpwd.html";
logout:function(){
window.localStorage.removeItem("token");
window.location = "login.html";
+ },
+ loginByTouchId: function() {
+ Fingerprint.isAvailable(function(result){
+ alert("Fingerprint available");
+ }, function(message){
+ alert(message);
+ });
}
};
app.initialize();
var dev = true;
-var SERVER = "";
+var SERVER = "http://ykt.supwisdom.com:10010/payapi/mobileapi";
var GLOBAL_TODAY="";
var GLOBAL_YESTERDAY="";
var CURRENT_INDEX=1;
if (dev) {
SERVER = "http://172.28.43.3:8099/payapi/mobileapi";
}
+function V1Qrcode(callback) {
+ ajaxPost("/v1/qrcode", {}, callback)
+}
+function V1Idtypes(callback) {
+ ajaxPost("/v1/idtypes", {}, callback)
+}
function V1Cardinfor(callback) {
ajaxPost("/v1/cardinfor", {}, callback)
}
<div style="display: flex;flex-direction: row;justify-content: center;align-items: center;margin-top: 50px;">
<div style="background: #fff;text-align: center;" id="qrcode"></div>
</div>
- <p style="text-align: center;margin-top:20px;color:#999">请将二维码对准扫描设备</p>
- <div style="padding: 30px;">
- <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="app.refresh()">手动刷新二维码</div>
- </div>
+ <p style="text-align: center;margin-top:40px;color:#999">请将二维码对准扫描设备</p>
+ <!--<div style="padding: 30px;">
+ <div class="aui-btn aui-btn-block aui-btn-info" tapmode onclick="window.location.reload();">刷新二维码</div>
+ </div>-->
</body>
</html>
<script type="text/javascript" src="cordova.js"></script>
<div class="aui-list-item-right"></div>
</div>
</li>
+ <!--<li class="aui-list-item" onclick="app.loginByTouchId()">
+ <div class="aui-list-item-label-icon">
+ <i class="aui-iconfont aui-icon-lock aui-text-info"></i>
+ </div>
+ <div class="aui-list-item-inner ">
+ <div class="aui-list-item-title">指纹\人脸登录</div>
+ <div class="aui-list-item-right"><input type="checkbox" id="login" class="aui-switch" ></div>
+ </div>
+ </li>-->
<li class="aui-list-item" onclick="app.toPayPwd()">
<div class="aui-list-item-label-icon">
<i class="aui-iconfont aui-icon-pencil aui-text-danger"></i>
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.apache.cordova.CallbackContext;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Map;
+import java.util.Set;
+
+import cn.jpush.android.api.CustomMessage;
+import cn.jpush.android.api.JPushInterface;
+import cn.jpush.android.api.JPushMessage;
+import cn.jpush.android.api.NotificationMessage;
+import cn.jpush.android.service.JPushMessageReceiver;
+
+public class JPushEventReceiver extends JPushMessageReceiver {
+
+ private static final String TAG = JPushEventReceiver.class.getSimpleName();
+
+ @Override
+ public void onTagOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onTagOperatorResult(context, jPushMessage);
+ //Log.e(TAG,"onTagOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) { // success
+ Set<String> tags = jPushMessage.getTags();
+ JSONArray tagsJsonArr = new JSONArray();
+ for (String tag : tags) {
+ tagsJsonArr.put(tag);
+ }
+
+ try {
+ if (tagsJsonArr.length() != 0) {
+ resultJson.put("tags", tagsJsonArr);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onCheckTagOperatorResult(context, jPushMessage);
+
+ //Log.e(TAG,"onCheckTagOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) {
+ try {
+ resultJson.put("tag", jPushMessage.getCheckTag());
+ resultJson.put("isBind", jPushMessage.getTagCheckStateResult());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onAliasOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onAliasOperatorResult(context, jPushMessage);
+
+ //Log.e(TAG,"onAliasOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) { // success
+ try {
+ if (!TextUtils.isEmpty(jPushMessage.getAlias())) {
+ resultJson.put("alias", jPushMessage.getAlias());
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onRegister(Context context, String regId) {
+ //Log.e(TAG,"onRegister:"+regId);
+ JPushPlugin.transmitReceiveRegistrationId(regId);
+ }
+
+ @Override
+ public void onMessage(Context context, CustomMessage customMessage) {
+ super.onMessage(context,customMessage);
+ //Log.e(TAG,"onMessage:"+customMessage);
+// String msg = customMessage.message;//intent.getStringExtra(JPushInterface.EXTRA_MESSAGE);
+// Map<String, Object> extras = getNotificationExtras(intent);
+// JPushPlugin.transmitMessageReceive(msg, extras);
+ }
+
+ @Override
+ public void onNotifyMessageArrived(Context context, NotificationMessage notificationMessage) {
+ super.onNotifyMessageArrived(context, notificationMessage);
+
+ //Log.e(TAG,"onNotifyMessageArrived:"+notificationMessage);
+ }
+
+ @Override
+ public void onNotifyMessageOpened(Context context, NotificationMessage notificationMessage) {
+ super.onNotifyMessageOpened(context, notificationMessage);
+ //Log.e(TAG,"onNotifyMessageOpened:"+notificationMessage);
+ }
+
+ @Override
+ public void onMobileNumberOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onMobileNumberOperatorResult(context, jPushMessage);
+ //Log.e(TAG,"onMobileNumberOperatorResult:"+jPushMessage);
+ }
+
+ @Override
+ public void onMultiActionClicked(Context context, Intent intent) {
+ super.onMultiActionClicked(context, intent);
+ //Log.e(TAG,"onMultiActionClicked:"+intent);
+ }
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import cn.jpush.android.api.BasicPushNotificationBuilder;
+import cn.jpush.android.api.JPushInterface;
+import cn.jpush.android.api.TagAliasCallback;
+import cn.jpush.android.data.JPushLocalNotification;
+
+public class JPushPlugin extends CordovaPlugin {
+
+ private static final String TAG = JPushPlugin.class.getSimpleName();
+
+ private Context mContext;
+
+ private static JPushPlugin instance;
+ private static Activity cordovaActivity;
+
+ static String notificationTitle;
+ static String notificationAlert;
+ static Map<String, Object> notificationExtras = new HashMap<String, Object>();
+
+ static String openNotificationTitle;
+ static String openNotificationAlert;
+ static Map<String, Object> openNotificationExtras = new HashMap<String, Object>();
+
+ static Map<Integer, CallbackContext> eventCallbackMap = new HashMap<Integer, CallbackContext>();
+
+ public JPushPlugin() {
+ instance = this;
+ }
+
+ @Override
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+ super.initialize(cordova, webView);
+ mContext = cordova.getActivity().getApplicationContext();
+
+ JPushInterface.init(mContext);
+
+ cordovaActivity = cordova.getActivity();
+
+ // 如果同时缓存了打开事件 openNotificationAlert 和 消息事件 notificationAlert,只向 UI 发打开事件。
+ // 这样做是为了和 iOS 统一。
+ if (openNotificationAlert != null) {
+ notificationAlert = null;
+ transmitNotificationOpen(openNotificationTitle, openNotificationAlert, openNotificationExtras);
+ }
+ if (notificationAlert != null) {
+ transmitNotificationReceive(notificationTitle, notificationAlert, notificationExtras);
+ }
+ }
+
+ public void onResume(boolean multitasking) {
+ if (openNotificationAlert != null) {
+ notificationAlert = null;
+ transmitNotificationOpen(openNotificationTitle, openNotificationAlert, openNotificationExtras);
+ }
+ if (notificationAlert != null) {
+ transmitNotificationReceive(notificationTitle, notificationAlert, notificationExtras);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ cordovaActivity = null;
+ instance = null;
+ }
+
+ private static JSONObject getMessageObject(String message, Map<String, Object> extras) {
+ JSONObject data = new JSONObject();
+ try {
+ data.put("message", message);
+ JSONObject jExtras = new JSONObject();
+ for (Entry<String, Object> entry : extras.entrySet()) {
+ if (entry.getKey().equals("cn.jpush.android.EXTRA")) {
+ JSONObject jo;
+ if (TextUtils.isEmpty((String) entry.getValue())) {
+ jo = new JSONObject();
+ } else {
+ jo = new JSONObject((String) entry.getValue());
+ String key;
+ Iterator keys = jo.keys();
+ while (keys.hasNext()) {
+ key = keys.next().toString();
+ jExtras.put(key, jo.getString(key));
+ }
+ }
+ jExtras.put("cn.jpush.android.EXTRA", jo);
+ } else {
+ jExtras.put(entry.getKey(), entry.getValue());
+ }
+ }
+ if (jExtras.length() > 0) {
+ data.put("extras", jExtras);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ private static JSONObject getNotificationObject(String title, String alert, Map<String, Object> extras) {
+ JSONObject data = new JSONObject();
+ try {
+ data.put("title", title);
+ data.put("alert", alert);
+ JSONObject jExtras = new JSONObject();
+ for (Entry<String, Object> entry : extras.entrySet()) {
+ if (entry.getKey().equals("cn.jpush.android.EXTRA")) {
+ JSONObject jo;
+ if (TextUtils.isEmpty((String) entry.getValue())) {
+ jo = new JSONObject();
+ } else {
+ jo = new JSONObject((String) entry.getValue());
+ String key;
+ Iterator keys = jo.keys();
+ while (keys.hasNext()) {
+ key = keys.next().toString();
+ jExtras.put(key, jo.getString(key));
+ }
+ }
+ jExtras.put("cn.jpush.android.EXTRA", jo);
+ } else {
+ jExtras.put(entry.getKey(), entry.getValue());
+ }
+ }
+ if (jExtras.length() > 0) {
+ data.put("extras", jExtras);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ static void transmitMessageReceive(String message, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getMessageObject(message, extras);
+ String format = "window.plugins.jPushPlugin.receiveMessageInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ }
+
+ static void transmitNotificationOpen(String title, String alert, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getNotificationObject(title, alert, extras);
+ String format = "window.plugins.jPushPlugin.openNotificationInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ JPushPlugin.openNotificationTitle = null;
+ JPushPlugin.openNotificationAlert = null;
+ }
+
+ static void transmitNotificationReceive(String title, String alert, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getNotificationObject(title, alert, extras);
+ String format = "window.plugins.jPushPlugin.receiveNotificationInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ JPushPlugin.notificationTitle = null;
+ JPushPlugin.notificationAlert = null;
+ }
+
+ static void transmitReceiveRegistrationId(String rId) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = new JSONObject();
+ try {
+ data.put("registrationId", rId);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ String format = "window.plugins.jPushPlugin.receiveRegistrationIdInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ }
+
+ @Override
+ public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext)
+ throws JSONException {
+ cordova.getThreadPool().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Method method = JPushPlugin.class.getDeclaredMethod(action, JSONArray.class, CallbackContext.class);
+ method.invoke(JPushPlugin.this, data, callbackContext);
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ });
+ return true;
+ }
+
+ void init(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.init(mContext);
+ }
+
+ void setDebugMode(JSONArray data, CallbackContext callbackContext) {
+ boolean mode;
+ try {
+ mode = data.getBoolean(0);
+ JPushInterface.setDebugMode(mode);
+ callbackContext.success();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ void stopPush(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.stopPush(mContext);
+ callbackContext.success();
+ }
+
+ void resumePush(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.resumePush(mContext);
+ callbackContext.success();
+ }
+
+ void isPushStopped(JSONArray data, CallbackContext callbackContext) {
+ boolean isStopped = JPushInterface.isPushStopped(mContext);
+ if (isStopped) {
+ callbackContext.success(1);
+ } else {
+ callbackContext.success(0);
+ }
+ }
+
+ void areNotificationEnabled(JSONArray data, final CallbackContext callback) {
+ int isEnabled;
+ if (hasPermission("OP_POST_NOTIFICATION")) {
+ isEnabled = 1;
+ } else {
+ isEnabled = 0;
+ }
+ callback.success(isEnabled);
+ }
+
+ void setLatestNotificationNum(JSONArray data, CallbackContext callbackContext) {
+ int num = -1;
+ try {
+ num = data.getInt(0);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading num json");
+ }
+ if (num != -1) {
+ JPushInterface.setLatestNotificationNumber(mContext, num);
+ } else {
+ callbackContext.error("error num");
+ }
+ }
+
+ void setPushTime(JSONArray data, CallbackContext callbackContext) {
+ Set<Integer> days = new HashSet<Integer>();
+ JSONArray dayArray;
+ int startHour = -1;
+ int endHour = -1;
+ try {
+ dayArray = data.getJSONArray(0);
+ for (int i = 0; i < dayArray.length(); i++) {
+ days.add(dayArray.getInt(i));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading days json");
+ }
+ try {
+ startHour = data.getInt(1);
+ endHour = data.getInt(2);
+ } catch (JSONException e) {
+ callbackContext.error("error reading hour json");
+ }
+ Context context = mContext;
+ JPushInterface.setPushTime(context, days, startHour, endHour);
+ callbackContext.success();
+ }
+
+ void getRegistrationID(JSONArray data, CallbackContext callbackContext) {
+ Context context = mContext;
+ String regID = JPushInterface.getRegistrationID(context);
+ callbackContext.success(regID);
+ }
+
+ void onResume(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.onResume(this.cordova.getActivity());
+ }
+
+ void onPause(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.onPause(this.cordova.getActivity());
+ }
+
+ void reportNotificationOpened(JSONArray data, CallbackContext callbackContext) {
+ try {
+ String msgID;
+ msgID = data.getString(0);
+ JPushInterface.reportNotificationOpened(this.cordova.getActivity(), msgID);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ void setAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ String alias = null;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ alias = params.getString("alias");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.setAlias(mContext, sequence, alias);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void deleteAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.deleteAlias(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.getAlias(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void setTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.setTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void addTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.addTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void deleteTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.deleteTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void cleanTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.cleanTags(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getAllTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.getAllTags(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void checkTagBindState(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ String tag = null;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ tag = params.getString("tag");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.checkTagBindState(mContext, sequence, tag);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getConnectionState(JSONArray data, CallbackContext callback) {
+ boolean isConnected = JPushInterface.getConnectionState(cordovaActivity.getApplicationContext());
+ if (isConnected) {
+ callback.success(1);
+ } else {
+ callback.success(0);
+ }
+ }
+
+ /**
+ * 自定义通知行为,声音、震动、呼吸灯等。
+ */
+ void setBasicPushNotificationBuilder(JSONArray data, CallbackContext callbackContext) {
+ BasicPushNotificationBuilder builder = new BasicPushNotificationBuilder(this.cordova.getActivity());
+ builder.developerArg0 = "Basic builder 1";
+ JPushInterface.setPushNotificationBuilder(1, builder);
+ JSONObject obj = new JSONObject();
+ try {
+ obj.put("id", 1);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 自定义推送通知栏样式,需要自己实现具体代码。 http://docs.jiguang.cn/client/android_tutorials/#_11
+ */
+ void setCustomPushNotificationBuilder(JSONArray data, CallbackContext callbackContext) {
+ // CustomPushNotificationBuilder builder = new CustomPushNotificationBuilder(
+ // this.cordova.getActivity(), R.layout.test_notification_layout,
+ // R.id.icon, R.id.title, R.id.text);
+ // JPushInterface.setPushNotificationBuilder(2, builder);
+ // JPushInterface.setDefaultPushNotificationBuilder(builder);
+ }
+
+ void clearAllNotification(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.clearAllNotifications(this.cordova.getActivity());
+ }
+
+ void clearNotificationById(JSONArray data, CallbackContext callbackContext) {
+ int notificationId = -1;
+ try {
+ notificationId = data.getInt(0);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading id json");
+ return;
+ }
+ if (notificationId != -1) {
+ JPushInterface.clearNotificationById(this.cordova.getActivity(), notificationId);
+ } else {
+ callbackContext.error("error id");
+ }
+ }
+
+ void addLocalNotification(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int builderId = data.getInt(0);
+ String content = data.getString(1);
+ String title = data.getString(2);
+ int notificationID = data.getInt(3);
+ int broadcastTime = data.getInt(4);
+ String extrasStr = data.isNull(5) ? "" : data.getString(5);
+ JSONObject extras = new JSONObject();
+ if (!extrasStr.isEmpty()) {
+ extras = new JSONObject(extrasStr);
+ }
+
+ JPushLocalNotification ln = new JPushLocalNotification();
+ ln.setBuilderId(builderId);
+ ln.setContent(content);
+ ln.setTitle(title);
+ ln.setNotificationId(notificationID);
+ ln.setBroadcastTime(System.currentTimeMillis() + broadcastTime);
+ ln.setExtras(extras.toString());
+
+ JPushInterface.addLocalNotification(this.cordova.getActivity(), ln);
+ }
+
+ void removeLocalNotification(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int notificationID = data.getInt(0);
+ JPushInterface.removeLocalNotification(this.cordova.getActivity(), notificationID);
+ }
+
+ void clearLocalNotifications(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.clearLocalNotifications(this.cordova.getActivity());
+ }
+
+ /**
+ * 设置通知静默时间 http://docs.jpush.io/client/android_api/#api_5
+ */
+ void setSilenceTime(JSONArray data, CallbackContext callbackContext) {
+ try {
+ int startHour = data.getInt(0);
+ int startMinute = data.getInt(1);
+ int endHour = data.getInt(2);
+ int endMinute = data.getInt(3);
+ if (!isValidHour(startHour) || !isValidMinute(startMinute)) {
+ callbackContext.error("开始时间数值错误");
+ return;
+ }
+ if (!isValidHour(endHour) || !isValidMinute(endMinute)) {
+ callbackContext.error("结束时间数值错误");
+ return;
+ }
+ JPushInterface.setSilenceTime(this.cordova.getActivity(), startHour, startMinute, endHour, endMinute);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error: reading json data.");
+ }
+ }
+
+ void setGeofenceInterval(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ long interval = data.getLong(0);
+ JPushInterface.setGeofenceInterval(this.cordova.getActivity(), interval);
+ }
+
+ void setMaxGeofenceNumber(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int maxNumber = data.getInt(0);
+ JPushInterface.setMaxGeofenceNumber(mContext, maxNumber);
+ }
+
+ private boolean isValidHour(int hour) {
+ return !(hour < 0 || hour > 23);
+ }
+
+ private boolean isValidMinute(int minute) {
+ return !(minute < 0 || minute > 59);
+ }
+
+ /**
+ * 用于 Android 6.0 以上系统申请权限,具体可参考:
+ * http://docs.Push.io/client/android_api/#android-60
+ */
+ void requestPermission(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.requestPermission(this.cordova.getActivity());
+ }
+
+ private final TagAliasCallback mTagWithAliasCallback = new TagAliasCallback() {
+ @Override
+ public void gotResult(int code, String alias, Set<String> tags) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = new JSONObject();
+ try {
+ data.put("resultCode", code);
+ data.put("tags", tags);
+ data.put("alias", alias);
+ final String jsEvent = String.format("cordova.fireDocumentEvent('jpush.setTagsWithAlias',%s)",
+ data.toString());
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + jsEvent);
+ }
+ });
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ private boolean hasPermission(String appOpsServiceId) {
+
+ Context context = cordova.getActivity().getApplicationContext();
+ if (Build.VERSION.SDK_INT >= 24) {
+ NotificationManager mNotificationManager = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ return mNotificationManager.areNotificationsEnabled();
+ } else {
+ AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ ApplicationInfo appInfo = context.getApplicationInfo();
+
+ String pkg = context.getPackageName();
+ int uid = appInfo.uid;
+ Class appOpsClazz;
+
+ try {
+ appOpsClazz = Class.forName(AppOpsManager.class.getName());
+ Method checkOpNoThrowMethod = appOpsClazz.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE,
+ String.class);
+ Field opValue = appOpsClazz.getDeclaredField(appOpsServiceId);
+ int value = opValue.getInt(Integer.class);
+ Object result = checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg);
+ return Integer.parseInt(result.toString()) == AppOpsManager.MODE_ALLOWED;
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return false;
+ }
+
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cn.jpush.android.api.JPushInterface;
+
+public class JPushReceiver extends BroadcastReceiver {
+
+ private static final List<String> IGNORED_EXTRAS_KEYS = Arrays.asList("cn.jpush.android.TITLE",
+ "cn.jpush.android.MESSAGE", "cn.jpush.android.APPKEY", "cn.jpush.android.NOTIFICATION_CONTENT_TITLE","key_show_entity","platform");
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(JPushInterface.ACTION_REGISTRATION_ID)) {
+ String rId = intent.getStringExtra(JPushInterface.EXTRA_REGISTRATION_ID);
+ JPushPlugin.transmitReceiveRegistrationId(rId);
+ } else if (action.equals(JPushInterface.ACTION_MESSAGE_RECEIVED)) {
+ handlingMessageReceive(intent);
+ } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_RECEIVED)) {
+ handlingNotificationReceive(context, intent);
+ } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_OPENED)) {
+ handlingNotificationOpen(context, intent);
+ }
+ }
+
+ private void handlingMessageReceive(Intent intent) {
+ String msg = intent.getStringExtra(JPushInterface.EXTRA_MESSAGE);
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.transmitMessageReceive(msg, extras);
+ }
+
+ private void handlingNotificationOpen(Context context, Intent intent) {
+ String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE);
+ JPushPlugin.openNotificationTitle = title;
+
+ String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT);
+ JPushPlugin.openNotificationAlert = alert;
+
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.openNotificationExtras = extras;
+
+ JPushPlugin.transmitNotificationOpen(title, alert, extras);
+
+ Intent launch = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
+ if (launch != null) {
+ launch.addCategory(Intent.CATEGORY_LAUNCHER);
+ launch.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ context.startActivity(launch);
+ }
+ }
+
+ private void handlingNotificationReceive(Context context, Intent intent) {
+ String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE);
+ JPushPlugin.notificationTitle = title;
+
+ String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT);
+ JPushPlugin.notificationAlert = alert;
+
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.notificationExtras = extras;
+
+ JPushPlugin.transmitNotificationReceive(title, alert, extras);
+ }
+
+ private Map<String, Object> getNotificationExtras(Intent intent) {
+ Map<String, Object> extrasMap = new HashMap<String, Object>();
+ for (String key : intent.getExtras().keySet()) {
+ if (!IGNORED_EXTRAS_KEYS.contains(key)) {
+ if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
+ extrasMap.put(key, intent.getIntExtra(key, 0));
+ } else {
+ extrasMap.put(key, intent.getStringExtra(key));
+ }
+ }
+ }
+ return extrasMap;
+ }
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import cn.jpush.android.service.JCommonService;
+
+public class PushService extends JCommonService {
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- 获得焦点但未按下时的背景图片 -->
+ <item
+ android:state_focused="true"
+ android:state_enabled="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/jpush_ic_richpush_actionbar_back" />
+ <!-- 按下时的背景图片 -->
+ <item
+ android:state_enabled="true"
+ android:state_pressed="true"
+ android:drawable="@android:color/darker_gray" />
+ <!-- 按下时的背景图片 -->
+ <item
+ android:state_enabled="true"
+ android:state_checked="true"
+ android:drawable="@android:color/darker_gray" />
+ <!-- 默认时的背景图片 -->
+ <item android:drawable="@drawable/jpush_ic_richpush_actionbar_back" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <!-- 背景 gradient是渐变,corners定义的是圆角 -->
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="#ffffff" />
+ </shape>
+ </item>
+
+ <!-- 进度条 -->
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <solid android:color="#4393ea" />
+ </shape>
+ </clip>
+ </item>
+
+</layer-list>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/popLayoutId"
+ style="@style/MyDialogStyle"
+ android:orientation="vertical"
+ android:layout_width="280dp"
+ android:layout_height="250dp" >
+
+ <WebView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/wvPopwin"/>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<cn.jpush.android.ui.FullScreenView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/actionbarLayoutId"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:id="@+id/rlRichpushTitleBar"
+ android:layout_width="match_parent"
+ android:layout_height="40.0dp"
+ android:background="#29313a">
+
+ <ImageButton
+ android:id="@+id/imgRichpushBtnBack"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="9dp"
+ android:layout_marginRight="10dp"
+ android:background="@drawable/jpush_richpush_btn_selector" />
+
+ <ImageView
+ android:id="@+id/imgView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@id/imgRichpushBtnBack"
+ android:clickable="false"
+ android:src="@drawable/jpush_ic_richpush_actionbar_divider" />
+
+ <TextView
+ android:id="@+id/tvRichpushTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="7dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/imgView"
+ android:clickable="false"
+ android:text=" "
+ android:textSize="20sp"
+ android:textColor="#ffffff" />
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@+id/pushPrograssBar"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:progress="0"
+ android:progressDrawable="@drawable/jpush_richpush_progressbar"
+ style="?android:attr/progressBarStyleHorizontal" />
+ <WebView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/fullWebView"
+ android:background="#000000" />
+
+</cn.jpush.android.ui.FullScreenView>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ android:id="@+id/push_root_view"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="4dp"
+ android:paddingTop="2dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ >
+
+ <ImageView
+ android:id="@+id/push_notification_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"/>
+ <RelativeLayout
+ android:id="@+id/push_notification_style_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:id="@+id/push_notification_layout_lefttop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/push_notification_small_icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginLeft="6dp"
+ android:scaleType="centerInside"/>
+ <TextView
+ android:id="@+id/push_notification_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:maxLines="1"
+ android:maxWidth="200dp"
+ android:maxLength="24"
+ android:textColor="@android:color/black"
+ android:textSize="12sp"/>
+ <TextView
+ android:id="@+id/push_notification_dot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:text="· "
+ android:textColor="@android:color/black"
+ android:textSize="20sp"/>
+ <TextView
+ android:maxLines="1"
+ android:id="@+id/push_notification_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:textSize="12sp"
+ />
+ </LinearLayout>
+
+
+ <ImageView
+ android:id="@+id/push_notification_big_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:scaleType="centerInside"/>
+
+ <TextView
+ android:id="@+id/push_notification_sub_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_layout_lefttop"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:visibility="gone"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="1"
+ />
+
+ <TextView
+ android:id="@+id/push_notification_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_sub_title"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="2"
+ android:ellipsize="end"
+ />
+ <TextView
+ android:id="@+id/push_notification_content_one_line"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_sub_title"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ />
+ </RelativeLayout>
+ <RelativeLayout
+ android:id="@+id/push_notification_style_1"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@+id/push_notification_style_1_big_icon"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:scaleType="centerInside"/>
+ <LinearLayout
+ android:layout_marginLeft="6dp"
+ android:layout_toRightOf="@+id/push_notification_style_1_big_icon"
+ android:orientation="vertical"
+ android:layout_centerVertical="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/push_notification_style_1_date"
+ android:textSize="12sp"
+ android:layout_alignParentRight="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/push_notification_style_1_title"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/push_notification_style_1_date"
+ android:textSize="12sp"
+ android:textStyle="bold"
+ android:maxLines="1"
+ android:layout_marginRight="8dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </RelativeLayout>
+ <TextView
+ android:id="@+id/push_notification_style_1_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="2"
+ android:ellipsize="end" />
+ </LinearLayout>
+ </RelativeLayout>
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="jg_channel_name_p_min">不重要</string>
+ <string name="jg_channel_name_p_low">不重要</string>
+ <string name="jg_channel_name_p_default">普通</string>
+ <string name="jg_channel_name_p_high">重要</string>
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="jg_channel_name_p_min">LOW</string>
+ <string name="jg_channel_name_p_low">LOW</string>
+ <string name="jg_channel_name_p_default">NORMAL</string>
+ <string name="jg_channel_name_p_high">HIGH</string>
+
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="MyDialogStyle">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowFrame">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+ <item name="android:backgroundDimEnabled">true</item>
+ </style>
+</resources>
\ No newline at end of file
<feature name="ThemeableBrowser">
<param name="android-package" value="com.initialxy.cordova.themeablebrowser.ThemeableBrowser" />
</feature>
+ <feature name="JPushPlugin">
+ <param name="android-package" value="cn.jiguang.cordova.push.JPushPlugin" />
+ </feature>
<name short="大理市民卡">dlapp</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
<preference name="loglevel" value="DEBUG" />
<preference name="AutoHideSplashScreen" value="true" />
<preference name="SplashScreenDelay" value="0" />
+ <preference name="SplashShowOnlyFirstTime" value="true" />
<preference name="ErrorUrl" value="error.html" />
<preference name="Orientation" value="portrait" />
<preference name="UseSwiftLanguageVersion" value="4.0" />
// in the individual module build.gradle files
classpath 'com.android.tools.build:gradle:3.3.0'
+
+
}
}
"clobbers": [
"cordova.ThemeableBrowser"
]
+ },
+ {
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
];
module.exports.metadata = {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
};
});
\ No newline at end of file
--- /dev/null
+cordova.define("cordova-plugin-firebasex.FirebasePlugin", function(require, exports, module) {
+var exec = require('cordova/exec');
+
+exports.getVerificationID = function (number, success, error) {
+ exec(success, error, "FirebasePlugin", "getVerificationID", [number]);
+};
+
+exports.getId = function (success, error) {
+ exec(success, error, "FirebasePlugin", "getId", []);
+};
+
+exports.getToken = function (success, error) {
+ exec(success, error, "FirebasePlugin", "getToken", []);
+};
+
+exports.onMessageReceived = function (success, error) {
+ exec(success, error, "FirebasePlugin", "onMessageReceived", []);
+};
+
+exports.onTokenRefresh = function (success, error) {
+ exec(success, error, "FirebasePlugin", "onTokenRefresh", []);
+};
+
+exports.setBadgeNumber = function (number, success, error) {
+ exec(success, error, "FirebasePlugin", "setBadgeNumber", [number]);
+};
+
+exports.getBadgeNumber = function (success, error) {
+ exec(success, error, "FirebasePlugin", "getBadgeNumber", []);
+};
+
+exports.subscribe = function (topic, success, error) {
+ exec(success, error, "FirebasePlugin", "subscribe", [topic]);
+};
+
+exports.unsubscribe = function (topic, success, error) {
+ exec(success, error, "FirebasePlugin", "unsubscribe", [topic]);
+};
+
+exports.unregister = function (success, error) {
+ exec(success, error, "FirebasePlugin", "unregister", []);
+};
+
+exports.logEvent = function (name, params, success, error) {
+ exec(success, error, "FirebasePlugin", "logEvent", [name, params]);
+};
+
+
+
+exports.setScreenName = function (name, success, error) {
+ exec(success, error, "FirebasePlugin", "setScreenName", [name]);
+};
+
+exports.setUserId = function (id, success, error) {
+ exec(success, error, "FirebasePlugin", "setUserId", [id]);
+};
+
+exports.setUserProperty = function (name, value, success, error) {
+ exec(success, error, "FirebasePlugin", "setUserProperty", [name, value]);
+};
+
+exports.activateFetched = function (success, error) {
+ exec(success, error, "FirebasePlugin", "activateFetched", []);
+};
+
+exports.fetch = function (cacheExpirationSeconds, success, error) {
+ var args = [];
+ if (typeof cacheExpirationSeconds === 'number') {
+ args.push(cacheExpirationSeconds);
+ } else {
+ error = success;
+ success = cacheExpirationSeconds;
+ }
+ exec(success, error, "FirebasePlugin", "fetch", args);
+};
+
+exports.getByteArray = function (key, success, error) {
+ exec(success, error, "FirebasePlugin", "getByteArray", [key]);
+};
+
+exports.getValue = function (key, success, error) {
+ exec(success, error, "FirebasePlugin", "getValue", [key]);
+};
+
+exports.getInfo = function (success, error) {
+ exec(success, error, "FirebasePlugin", "getInfo", []);
+};
+
+exports.setConfigSettings = function (settings, success, error) {
+ exec(success, error, "FirebasePlugin", "setConfigSettings", [settings]);
+};
+
+exports.setDefaults = function (defaults, success, error) {
+ exec(success, error, "FirebasePlugin", "setDefaults", [defaults]);
+};
+
+exports.startTrace = function (name, success, error) {
+ exec(success, error, "FirebasePlugin", "startTrace", [name]);
+};
+
+exports.incrementCounter = function (name, counterNamed, success, error) {
+ exec(success, error, "FirebasePlugin", "incrementCounter", [name, counterNamed]);
+};
+
+exports.stopTrace = function (name, success, error) {
+ exec(success, error, "FirebasePlugin", "stopTrace", [name]);
+};
+
+exports.setAnalyticsCollectionEnabled = function (enabled, success, error) {
+ exec(success, error, "FirebasePlugin", "setAnalyticsCollectionEnabled", [enabled]);
+};
+
+exports.setPerformanceCollectionEnabled = function (enabled, success, error) {
+ exec(success, error, "FirebasePlugin", "setPerformanceCollectionEnabled", [enabled]);
+};
+
+exports.verifyPhoneNumber = function (number, timeOutDuration, success, error) {
+ if (typeof timeOutDuration === 'function') {
+ // method being called with old signature: function(number, success, error)
+ // timeOutDuration is the success callback, success is the error callback
+ exec(timeOutDuration, success, "FirebasePlugin", "verifyPhoneNumber", [number]);
+ } else {
+ // method being called with new signature: function(number, timeOutDuration, success, error)
+ // callbacks are correctly named
+ exec(success, error, "FirebasePlugin", "verifyPhoneNumber", [number, timeOutDuration]);
+ }
+};
+
+exports.clearAllNotifications = function (success, error) {
+ exec(success, error, "FirebasePlugin", "clearAllNotifications", []);
+};
+
+
+// Crashlytics
+exports.logMessage = function (message, success, error) {
+ exec(success, error, "FirebasePlugin", "logMessage", [message]);
+};
+
+exports.sendCrash = function (success, error) {
+ exec(success, error, "FirebasePlugin", "sendCrash", []);
+};
+
+exports.logError = function (message, stackTrace, success, error) {
+ var args = [message];
+ // "stackTrace" is an optional arg that's an array of objects.
+ if (stackTrace) {
+ if (typeof stackTrace === 'function') {
+ error = success;
+ success = stackTrace;
+ } else {
+ args.push(stackTrace);
+ }
+ }
+ exec(success, error, "FirebasePlugin", "logError", args);
+};
+
+exports.setCrashlyticsUserId = function (userId, success, error) {
+ exec(success, error, "FirebasePlugin", "setCrashlyticsUserId", [userId]);
+};
+
+// iOS-only
+exports.grantPermission = function (success, error) {
+ exec(success, error, "FirebasePlugin", "grantPermission", []);
+};
+
+exports.hasPermission = function (success, error) {
+ exec(success, error, "FirebasePlugin", "hasPermission", []);
+};
+
+// Android-only
+exports.setDefaultChannel = function (options, success, error) {
+ exec(success, error, "FirebasePlugin", "setDefaultChannel", [options]);
+};
+
+exports.createChannel = function (options, success, error) {
+ exec(success, error, "FirebasePlugin", "createChannel", [options]);
+};
+
+exports.deleteChannel = function (channelID, success, error) {
+ exec(success, error, "FirebasePlugin", "deleteChannel", [channelID]);
+};
+
+exports.listChannels = function (success, error) {
+ exec(success, error, "FirebasePlugin", "listChannels", []);
+};
+
+});
--- /dev/null
+cordova.define("jpush-phonegap-plugin.JPushPlugin", function(require, exports, module) {
+var JPushPlugin = function() {};
+
+// private plugin function
+
+JPushPlugin.prototype.receiveMessage = {};
+JPushPlugin.prototype.openNotification = {};
+JPushPlugin.prototype.receiveNotification = {};
+
+JPushPlugin.prototype.isPlatformIOS = function() {
+ return (
+ device.platform === "iPhone" ||
+ device.platform === "iPad" ||
+ device.platform === "iPod touch" ||
+ device.platform === "iOS"
+ );
+};
+
+JPushPlugin.prototype.errorCallback = function(msg) {
+ console.log("JPush Callback Error: " + msg);
+};
+
+JPushPlugin.prototype.callNative = function(
+ name,
+ args,
+ successCallback,
+ errorCallback
+) {
+ if (errorCallback) {
+ cordova.exec(successCallback, errorCallback, "JPushPlugin", name, args);
+ } else {
+ cordova.exec(
+ successCallback,
+ this.errorCallback,
+ "JPushPlugin",
+ name,
+ args
+ );
+ }
+};
+
+// Common methods
+JPushPlugin.prototype.init = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("initial", [], null);
+ } else {
+ this.callNative("init", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugMode = function(mode) {
+ if (device.platform === "Android") {
+ this.callNative("setDebugMode", [mode], null);
+ } else {
+ if (mode === true) {
+ this.setDebugModeFromIos();
+ } else {
+ this.setLogOFF();
+ }
+ }
+};
+
+JPushPlugin.prototype.getRegistrationID = function(successCallback) {
+ this.callNative("getRegistrationID", [], successCallback);
+};
+
+JPushPlugin.prototype.stopPush = function() {
+ this.callNative("stopPush", [], null);
+};
+
+JPushPlugin.prototype.resumePush = function() {
+ this.callNative("resumePush", [], null);
+};
+
+JPushPlugin.prototype.isPushStopped = function(successCallback) {
+ this.callNative("isPushStopped", [], successCallback);
+};
+
+JPushPlugin.prototype.clearLocalNotifications = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearLocalNotifications", [], null);
+ } else {
+ this.clearAllLocalNotifications();
+ }
+};
+
+/**
+ * 设置标签。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.setTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 新增标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.addTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("addTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除指定标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.deleteTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 清除所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.cleanTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("cleanTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAllTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAllTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询指定标签与当前用户的绑定状态。
+ *
+ * @param params = { 'sequence': number, 'tag': string }
+ */
+JPushPlugin.prototype.checkTagBindState = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative(
+ "checkTagBindState",
+ [params],
+ successCallback,
+ errorCallback
+ );
+};
+
+/**
+ * 设置别名。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'alias': string }
+ */
+JPushPlugin.prototype.setAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.deleteAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询当前绑定的别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAlias", [params], successCallback, errorCallback);
+};
+
+// 判断系统设置中是否对本应用启用通知。
+// iOS: 返回值如果大于 0,代表通知开启;0: 通知关闭。
+// UIRemoteNotificationTypeNone = 0,
+// UIRemoteNotificationTypeBadge = 1 << 0,
+// UIRemoteNotificationTypeSound = 1 << 1,
+// UIRemoteNotificationTypeAlert = 1 << 2,
+// UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
+// Android: 返回值 1 代表通知启用;0: 通知关闭。
+JPushPlugin.prototype.getUserNotificationSettings = function(successCallback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getUserNotificationSettings", [], successCallback);
+ } else if (device.platform === "Android") {
+ this.callNative("areNotificationEnabled", [], successCallback);
+ }
+};
+
+// iOS methods
+
+JPushPlugin.prototype.startJPushSDK = function() {
+ this.callNative("startJPushSDK", [], null);
+};
+
+JPushPlugin.prototype.setBadge = function(value) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setBadge", [value], null);
+ }
+};
+
+JPushPlugin.prototype.resetBadge = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("resetBadge", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugModeFromIos = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setDebugModeFromIos", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLogOFF = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLogOFF", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCrashLogON = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("crashLogON", [], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotificationForIOS = function(
+ delayTime,
+ content,
+ badge,
+ notificationID,
+ extras
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "setLocalNotification",
+ [delayTime, content, badge, notificationID, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function(
+ identifierKey
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "deleteLocalNotificationWithIdentifierKey",
+ [identifierKey],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.clearAllLocalNotifications = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("clearAllLocalNotifications", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLocation = function(latitude, longitude) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLocation", [latitude, longitude], null);
+ }
+};
+
+JPushPlugin.prototype.startLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("startLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.stopLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("stopLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.beginLogPageView = function(pageName, duration) {
+ if (this.isPlatformIOS()) {
+ this.callNative("beginLogPageView", [pageName, duration], null);
+ }
+};
+
+JPushPlugin.prototype.setApplicationIconBadgeNumber = function(badge) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setApplicationIconBadgeNumber", [badge], null);
+ }
+};
+
+JPushPlugin.prototype.getApplicationIconBadgeNumber = function(callback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getApplicationIconBadgeNumber", [], callback);
+ }
+};
+
+JPushPlugin.prototype.addDismissActions = function(actions, categoryId) {
+ this.callNative("addDismissActions", [actions, categoryId]);
+};
+
+JPushPlugin.prototype.addNotificationActions = function(actions, categoryId) {
+ this.callNative("addNotificationActions", [actions, categoryId]);
+};
+
+// Android methods
+JPushPlugin.prototype.getConnectionState = function(successCallback) {
+ if (device.platform === "Android") {
+ this.callNative("getConnectionState", [], successCallback);
+ }
+};
+
+JPushPlugin.prototype.setBasicPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setBasicPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCustomPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setCustomPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.receiveRegistrationIdInAndroidCallback = function(data) {
+ if (device.platform === "Android") {
+ data = JSON.stringify(data);
+ var event = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveRegistrationId", event);
+ }
+};
+
+JPushPlugin.prototype.receiveMessageInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveMessage = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveMessage", this.receiveMessage);
+};
+
+JPushPlugin.prototype.openNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.openNotification = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.openNotification", this.openNotification);
+};
+
+JPushPlugin.prototype.receiveNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveNotification = JSON.parse(data);
+ cordova.fireDocumentEvent(
+ "jpush.receiveNotification",
+ this.receiveNotification
+ );
+};
+
+JPushPlugin.prototype.clearAllNotification = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearAllNotification", [], null);
+ }
+};
+
+JPushPlugin.prototype.clearNotificationById = function(id) {
+ if (device.platform === "Android") {
+ this.callNative("clearNotificationById", [id], null);
+ }
+};
+
+JPushPlugin.prototype.setLatestNotificationNum = function(num) {
+ if (device.platform === "Android") {
+ this.callNative("setLatestNotificationNum", [num], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotification = function(
+ builderId,
+ content,
+ title,
+ notificationID,
+ broadcastTime,
+ extras
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "addLocalNotification",
+ [builderId, content, title, notificationID, broadcastTime, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.removeLocalNotification = function(notificationID) {
+ if (device.platform === "Android") {
+ this.callNative("removeLocalNotification", [notificationID], null);
+ }
+};
+
+JPushPlugin.prototype.reportNotificationOpened = function(msgID) {
+ if (device.platform === "Android") {
+ this.callNative("reportNotificationOpened", [msgID], null);
+ }
+};
+
+/**
+ * 用于在 Android 6.0 及以上系统,申请一些权限
+ * 具体可看:http://docs.jpush.io/client/android_api/#android-60
+ */
+JPushPlugin.prototype.requestPermission = function() {
+ if (device.platform === "Android") {
+ this.callNative("requestPermission", [], null);
+ }
+};
+
+JPushPlugin.prototype.setSilenceTime = function(
+ startHour,
+ startMinute,
+ endHour,
+ endMinute
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "setSilenceTime",
+ [startHour, startMinute, endHour, endMinute],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.setPushTime = function(weekdays, startHour, endHour) {
+ if (device.platform === "Android") {
+ this.callNative("setPushTime", [weekdays, startHour, endHour], null);
+ }
+};
+
+JPushPlugin.prototype.setGeofenceInterval = function(interval) {
+ if (device.platform === "Android") {
+ this.callNative("setGeofenceInterval", [interval], null);
+ }
+};
+
+JPushPlugin.prototype.setMaxGeofenceNumber = function(maxNumber) {
+ if (device.platform === "Android") {
+ this.callNative("setMaxGeofenceNumber", [maxNumber], null);
+ }
+};
+
+if (!window.plugins) {
+ window.plugins = {};
+}
+
+if (!window.plugins.jPushPlugin) {
+ window.plugins.jPushPlugin = new JPushPlugin();
+}
+
+module.exports = new JPushPlugin();
+
+});
android.library.reference.2=app
cordova.system.library.1=com.squareup.okhttp3:okhttp-urlconnection:3.10.0
cordova.gradle.include.1=cordova-plugin-qrscanner/dlapp-qrscanner.gradle
-cordova.system.library.2=com.android.support:support-v4:24.1.1+
\ No newline at end of file
+cordova.system.library.2=com.android.support:support-v4:24.1.1+
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
},
"dependent_plugins": {},
"id": "cordova-plugin-device.DeviceProxy",
"pluginId": "cordova-plugin-device",
"runs": true
+ },
+ {
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
],
"plugin_metadata": {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
}
}
</edit-config>
<preference name="AutoHideSplashScreen" value="true" />
<preference name="SplashScreenDelay" value="0" />
+ <preference name="SplashShowOnlyFirstTime" value="true" />
<preference name="ErrorUrl" value="error.html" />
<preference name="Orientation" value="portrait" />
<preference name="UseSwiftLanguageVersion" value="4.0" />
"id": "cordova-plugin-device.DeviceProxy",
"pluginId": "cordova-plugin-device",
"runs": true
+ },
+ {
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
];
module.exports.metadata =
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
}
// BOTTOM OF METADATA
});
\ No newline at end of file
--- /dev/null
+cordova.define("jpush-phonegap-plugin.JPushPlugin", function(require, exports, module) { var JPushPlugin = function() {};
+
+// private plugin function
+
+JPushPlugin.prototype.receiveMessage = {};
+JPushPlugin.prototype.openNotification = {};
+JPushPlugin.prototype.receiveNotification = {};
+
+JPushPlugin.prototype.isPlatformIOS = function() {
+ return (
+ device.platform === "iPhone" ||
+ device.platform === "iPad" ||
+ device.platform === "iPod touch" ||
+ device.platform === "iOS"
+ );
+};
+
+JPushPlugin.prototype.errorCallback = function(msg) {
+ console.log("JPush Callback Error: " + msg);
+};
+
+JPushPlugin.prototype.callNative = function(
+ name,
+ args,
+ successCallback,
+ errorCallback
+) {
+ if (errorCallback) {
+ cordova.exec(successCallback, errorCallback, "JPushPlugin", name, args);
+ } else {
+ cordova.exec(
+ successCallback,
+ this.errorCallback,
+ "JPushPlugin",
+ name,
+ args
+ );
+ }
+};
+
+// Common methods
+JPushPlugin.prototype.init = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("initial", [], null);
+ } else {
+ this.callNative("init", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugMode = function(mode) {
+ if (device.platform === "Android") {
+ this.callNative("setDebugMode", [mode], null);
+ } else {
+ if (mode === true) {
+ this.setDebugModeFromIos();
+ } else {
+ this.setLogOFF();
+ }
+ }
+};
+
+JPushPlugin.prototype.getRegistrationID = function(successCallback) {
+ this.callNative("getRegistrationID", [], successCallback);
+};
+
+JPushPlugin.prototype.stopPush = function() {
+ this.callNative("stopPush", [], null);
+};
+
+JPushPlugin.prototype.resumePush = function() {
+ this.callNative("resumePush", [], null);
+};
+
+JPushPlugin.prototype.isPushStopped = function(successCallback) {
+ this.callNative("isPushStopped", [], successCallback);
+};
+
+JPushPlugin.prototype.clearLocalNotifications = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearLocalNotifications", [], null);
+ } else {
+ this.clearAllLocalNotifications();
+ }
+};
+
+/**
+ * 设置标签。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.setTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 新增标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.addTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("addTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除指定标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.deleteTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 清除所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.cleanTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("cleanTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAllTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAllTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询指定标签与当前用户的绑定状态。
+ *
+ * @param params = { 'sequence': number, 'tag': string }
+ */
+JPushPlugin.prototype.checkTagBindState = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative(
+ "checkTagBindState",
+ [params],
+ successCallback,
+ errorCallback
+ );
+};
+
+/**
+ * 设置别名。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'alias': string }
+ */
+JPushPlugin.prototype.setAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.deleteAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询当前绑定的别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAlias", [params], successCallback, errorCallback);
+};
+
+// 判断系统设置中是否对本应用启用通知。
+// iOS: 返回值如果大于 0,代表通知开启;0: 通知关闭。
+// UIRemoteNotificationTypeNone = 0,
+// UIRemoteNotificationTypeBadge = 1 << 0,
+// UIRemoteNotificationTypeSound = 1 << 1,
+// UIRemoteNotificationTypeAlert = 1 << 2,
+// UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
+// Android: 返回值 1 代表通知启用;0: 通知关闭。
+JPushPlugin.prototype.getUserNotificationSettings = function(successCallback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getUserNotificationSettings", [], successCallback);
+ } else if (device.platform === "Android") {
+ this.callNative("areNotificationEnabled", [], successCallback);
+ }
+};
+
+// iOS methods
+
+JPushPlugin.prototype.startJPushSDK = function() {
+ this.callNative("startJPushSDK", [], null);
+};
+
+JPushPlugin.prototype.setBadge = function(value) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setBadge", [value], null);
+ }
+};
+
+JPushPlugin.prototype.resetBadge = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("resetBadge", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugModeFromIos = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setDebugModeFromIos", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLogOFF = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLogOFF", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCrashLogON = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("crashLogON", [], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotificationForIOS = function(
+ delayTime,
+ content,
+ badge,
+ notificationID,
+ extras
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "setLocalNotification",
+ [delayTime, content, badge, notificationID, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function(
+ identifierKey
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "deleteLocalNotificationWithIdentifierKey",
+ [identifierKey],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.clearAllLocalNotifications = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("clearAllLocalNotifications", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLocation = function(latitude, longitude) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLocation", [latitude, longitude], null);
+ }
+};
+
+JPushPlugin.prototype.startLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("startLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.stopLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("stopLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.beginLogPageView = function(pageName, duration) {
+ if (this.isPlatformIOS()) {
+ this.callNative("beginLogPageView", [pageName, duration], null);
+ }
+};
+
+JPushPlugin.prototype.setApplicationIconBadgeNumber = function(badge) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setApplicationIconBadgeNumber", [badge], null);
+ }
+};
+
+JPushPlugin.prototype.getApplicationIconBadgeNumber = function(callback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getApplicationIconBadgeNumber", [], callback);
+ }
+};
+
+JPushPlugin.prototype.addDismissActions = function(actions, categoryId) {
+ this.callNative("addDismissActions", [actions, categoryId]);
+};
+
+JPushPlugin.prototype.addNotificationActions = function(actions, categoryId) {
+ this.callNative("addNotificationActions", [actions, categoryId]);
+};
+
+// Android methods
+JPushPlugin.prototype.getConnectionState = function(successCallback) {
+ if (device.platform === "Android") {
+ this.callNative("getConnectionState", [], successCallback);
+ }
+};
+
+JPushPlugin.prototype.setBasicPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setBasicPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCustomPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setCustomPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.receiveRegistrationIdInAndroidCallback = function(data) {
+ if (device.platform === "Android") {
+ data = JSON.stringify(data);
+ var event = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveRegistrationId", event);
+ }
+};
+
+JPushPlugin.prototype.receiveMessageInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveMessage = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveMessage", this.receiveMessage);
+};
+
+JPushPlugin.prototype.openNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.openNotification = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.openNotification", this.openNotification);
+};
+
+JPushPlugin.prototype.receiveNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveNotification = JSON.parse(data);
+ cordova.fireDocumentEvent(
+ "jpush.receiveNotification",
+ this.receiveNotification
+ );
+};
+
+JPushPlugin.prototype.clearAllNotification = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearAllNotification", [], null);
+ }
+};
+
+JPushPlugin.prototype.clearNotificationById = function(id) {
+ if (device.platform === "Android") {
+ this.callNative("clearNotificationById", [id], null);
+ }
+};
+
+JPushPlugin.prototype.setLatestNotificationNum = function(num) {
+ if (device.platform === "Android") {
+ this.callNative("setLatestNotificationNum", [num], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotification = function(
+ builderId,
+ content,
+ title,
+ notificationID,
+ broadcastTime,
+ extras
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "addLocalNotification",
+ [builderId, content, title, notificationID, broadcastTime, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.removeLocalNotification = function(notificationID) {
+ if (device.platform === "Android") {
+ this.callNative("removeLocalNotification", [notificationID], null);
+ }
+};
+
+JPushPlugin.prototype.reportNotificationOpened = function(msgID) {
+ if (device.platform === "Android") {
+ this.callNative("reportNotificationOpened", [msgID], null);
+ }
+};
+
+/**
+ * 用于在 Android 6.0 及以上系统,申请一些权限
+ * 具体可看:http://docs.jpush.io/client/android_api/#android-60
+ */
+JPushPlugin.prototype.requestPermission = function() {
+ if (device.platform === "Android") {
+ this.callNative("requestPermission", [], null);
+ }
+};
+
+JPushPlugin.prototype.setSilenceTime = function(
+ startHour,
+ startMinute,
+ endHour,
+ endMinute
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "setSilenceTime",
+ [startHour, startMinute, endHour, endMinute],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.setPushTime = function(weekdays, startHour, endHour) {
+ if (device.platform === "Android") {
+ this.callNative("setPushTime", [weekdays, startHour, endHour], null);
+ }
+};
+
+JPushPlugin.prototype.setGeofenceInterval = function(interval) {
+ if (device.platform === "Android") {
+ this.callNative("setGeofenceInterval", [interval], null);
+ }
+};
+
+JPushPlugin.prototype.setMaxGeofenceNumber = function(maxNumber) {
+ if (device.platform === "Android") {
+ this.callNative("setMaxGeofenceNumber", [maxNumber], null);
+ }
+};
+
+if (!window.plugins) {
+ window.plugins = {};
+}
+
+if (!window.plugins.jPushPlugin) {
+ window.plugins.jPushPlugin = new JPushPlugin();
+}
+
+module.exports = new JPushPlugin();
+
+});
--- /dev/null
+PODFILE CHECKSUM: e5038167266107ffa86081c2bbb7148c097e71eb
+
+COCOAPODS: 1.5.2
--- /dev/null
+PODFILE CHECKSUM: e5038167266107ffa86081c2bbb7148c097e71eb
+
+COCOAPODS: 1.5.2
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 643D3B1E52B2984E46E7B2242856084D /* Pods-dlapp-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1154D50C03F2C4A4D1E1A6A35A4580D9 /* Pods-dlapp-dummy.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 0B9FDFC65AF777A68D74F86F830E8D29 /* libPods-dlapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = "libPods-dlapp.a"; path = "libPods-dlapp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1154D50C03F2C4A4D1E1A6A35A4580D9 /* Pods-dlapp-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dlapp-dummy.m"; sourceTree = "<group>"; };
+ 53416009C0EB96589449A0D152302159 /* Pods-dlapp-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-dlapp-acknowledgements.markdown"; sourceTree = "<group>"; };
+ 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
+ AF5E9BBF20F1C626FFD56F1ACC2A945D /* Pods-dlapp-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-dlapp-frameworks.sh"; sourceTree = "<group>"; };
+ CB6583549252874668D1D65B0EC3158C /* Pods-dlapp-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-dlapp-resources.sh"; sourceTree = "<group>"; };
+ D2031FC780E4135865DBAC7B0BECDA29 /* Pods-dlapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-dlapp.debug.xcconfig"; sourceTree = "<group>"; };
+ E60AB409C8228577C8314E69A54EC524 /* Pods-dlapp-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-dlapp-acknowledgements.plist"; sourceTree = "<group>"; };
+ EEC91C98D2D922E40FAE18A4F04D83AE /* Pods-dlapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-dlapp.release.xcconfig"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8C1A83A20A9DA90317678291D8688BF5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 0F8D2E47FE03D3B91B51069F7C273AF4 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 548BE5040BA5F7460A0477C20076FED1 /* Pods-dlapp */ = {
+ isa = PBXGroup;
+ children = (
+ 53416009C0EB96589449A0D152302159 /* Pods-dlapp-acknowledgements.markdown */,
+ E60AB409C8228577C8314E69A54EC524 /* Pods-dlapp-acknowledgements.plist */,
+ 1154D50C03F2C4A4D1E1A6A35A4580D9 /* Pods-dlapp-dummy.m */,
+ AF5E9BBF20F1C626FFD56F1ACC2A945D /* Pods-dlapp-frameworks.sh */,
+ CB6583549252874668D1D65B0EC3158C /* Pods-dlapp-resources.sh */,
+ D2031FC780E4135865DBAC7B0BECDA29 /* Pods-dlapp.debug.xcconfig */,
+ EEC91C98D2D922E40FAE18A4F04D83AE /* Pods-dlapp.release.xcconfig */,
+ );
+ name = "Pods-dlapp";
+ path = "Target Support Files/Pods-dlapp";
+ sourceTree = "<group>";
+ };
+ 7DB346D0F39D3F0E887471402A8071AB = {
+ isa = PBXGroup;
+ children = (
+ 93A4A3777CF96A4AAC1D13BA6DCCEA73 /* Podfile */,
+ 0F8D2E47FE03D3B91B51069F7C273AF4 /* Frameworks */,
+ C2B1D5AB28132D1F1EC74A313228649B /* Products */,
+ ABF54CA5D18420FEA3DD9419BE3E157A /* Targets Support Files */,
+ );
+ sourceTree = "<group>";
+ };
+ ABF54CA5D18420FEA3DD9419BE3E157A /* Targets Support Files */ = {
+ isa = PBXGroup;
+ children = (
+ 548BE5040BA5F7460A0477C20076FED1 /* Pods-dlapp */,
+ );
+ name = "Targets Support Files";
+ sourceTree = "<group>";
+ };
+ C2B1D5AB28132D1F1EC74A313228649B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 0B9FDFC65AF777A68D74F86F830E8D29 /* libPods-dlapp.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 095FEF9C74B1A68F66A3061771703C06 /* Pods-dlapp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F6A3DDA2CD5F1F9A4AEF4D6F6662EAD9 /* Build configuration list for PBXNativeTarget "Pods-dlapp" */;
+ buildPhases = (
+ A54DF46585559C2430C5DDBBDB2D11FF /* Sources */,
+ 8C1A83A20A9DA90317678291D8688BF5 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Pods-dlapp";
+ productName = "Pods-dlapp";
+ productReference = 0B9FDFC65AF777A68D74F86F830E8D29 /* libPods-dlapp.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ D41D8CD98F00B204E9800998ECF8427E /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0930;
+ LastUpgradeCheck = 0930;
+ };
+ buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 7DB346D0F39D3F0E887471402A8071AB;
+ productRefGroup = C2B1D5AB28132D1F1EC74A313228649B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 095FEF9C74B1A68F66A3061771703C06 /* Pods-dlapp */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ A54DF46585559C2430C5DDBBDB2D11FF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 643D3B1E52B2984E46E7B2242856084D /* Pods-dlapp-dummy.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 199D972A13F2B4C56847F7A89CCA83BC /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGNING_ALLOWED = NO;
+ CODE_SIGNING_REQUIRED = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "POD_CONFIGURATION_DEBUG=1",
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ STRIP_INSTALLED_PRODUCT = NO;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SYMROOT = "${SRCROOT}/../build";
+ };
+ name = Debug;
+ };
+ CB0C4A0438BB41F9A7F1E080D5B2AD40 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = D2031FC780E4135865DBAC7B0BECDA29 /* Pods-dlapp.debug.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MACH_O_TYPE = staticlib;
+ OTHER_LDFLAGS = "";
+ OTHER_LIBTOOLFLAGS = "";
+ PODS_ROOT = "$(SRCROOT)";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+ SDKROOT = iphoneos;
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ D410F425008A083F9E9694725B8E89FB /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = EEC91C98D2D922E40FAE18A4F04D83AE /* Pods-dlapp.release.xcconfig */;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
+ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MACH_O_TYPE = staticlib;
+ OTHER_LDFLAGS = "";
+ OTHER_LIBTOOLFLAGS = "";
+ PODS_ROOT = "$(SRCROOT)";
+ PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
+ SDKROOT = iphoneos;
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ FDB2FC4A1E5891381CD9D922145497F1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGNING_ALLOWED = NO;
+ CODE_SIGNING_REQUIRED = NO;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "POD_CONFIGURATION_RELEASE=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ STRIP_INSTALLED_PRODUCT = NO;
+ SYMROOT = "${SRCROOT}/../build";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 199D972A13F2B4C56847F7A89CCA83BC /* Debug */,
+ FDB2FC4A1E5891381CD9D922145497F1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F6A3DDA2CD5F1F9A4AEF4D6F6662EAD9 /* Build configuration list for PBXNativeTarget "Pods-dlapp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CB0C4A0438BB41F9A7F1E080D5B2AD40 /* Debug */,
+ D410F425008A083F9E9694725B8E89FB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */;
+}
--- /dev/null
+# Acknowledgements
+This application makes use of the following third party libraries:
+Generated by CocoaPods - https://cocoapods.org
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>PreferenceSpecifiers</key>
+ <array>
+ <dict>
+ <key>FooterText</key>
+ <string>This application makes use of the following third party libraries:</string>
+ <key>Title</key>
+ <string>Acknowledgements</string>
+ <key>Type</key>
+ <string>PSGroupSpecifier</string>
+ </dict>
+ <dict>
+ <key>FooterText</key>
+ <string>Generated by CocoaPods - https://cocoapods.org</string>
+ <key>Title</key>
+ <string></string>
+ <key>Type</key>
+ <string>PSGroupSpecifier</string>
+ </dict>
+ </array>
+ <key>StringsTable</key>
+ <string>Acknowledgements</string>
+ <key>Title</key>
+ <string>Acknowledgements</string>
+</dict>
+</plist>
--- /dev/null
+#import <Foundation/Foundation.h>
+@interface PodsDummy_Pods_dlapp : NSObject
+@end
+@implementation PodsDummy_Pods_dlapp
+@end
--- /dev/null
+#!/bin/sh
+set -e
+set -u
+set -o pipefail
+
+if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
+ # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
+ # frameworks to, so exit 0 (signalling the script phase was successful).
+ exit 0
+fi
+
+echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
+SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
+
+# Used as a return value for each invocation of `strip_invalid_archs` function.
+STRIP_BINARY_RETVAL=0
+
+# This protects against multiple targets copying the same framework dependency at the same time. The solution
+# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
+RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
+
+# Copies and strips a vendored framework
+install_framework()
+{
+ if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
+ local source="${BUILT_PRODUCTS_DIR}/$1"
+ elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
+ local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
+ elif [ -r "$1" ]; then
+ local source="$1"
+ fi
+
+ local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+
+ if [ -L "${source}" ]; then
+ echo "Symlinked..."
+ source="$(readlink "${source}")"
+ fi
+
+ # Use filter instead of exclude so missing patterns don't throw errors.
+ echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
+ rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
+
+ local basename
+ basename="$(basename -s .framework "$1")"
+ binary="${destination}/${basename}.framework/${basename}"
+ if ! [ -r "$binary" ]; then
+ binary="${destination}/${basename}"
+ fi
+
+ # Strip invalid architectures so "fat" simulator / device frameworks work on device
+ if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
+ strip_invalid_archs "$binary"
+ fi
+
+ # Resign the code if required by the build settings to avoid unstable apps
+ code_sign_if_enabled "${destination}/$(basename "$1")"
+
+ # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
+ if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
+ local swift_runtime_libs
+ swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
+ for lib in $swift_runtime_libs; do
+ echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
+ rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
+ code_sign_if_enabled "${destination}/${lib}"
+ done
+ fi
+}
+
+# Copies and strips a vendored dSYM
+install_dsym() {
+ local source="$1"
+ if [ -r "$source" ]; then
+ # Copy the dSYM into a the targets temp dir.
+ echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
+ rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
+
+ local basename
+ basename="$(basename -s .framework.dSYM "$source")"
+ binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
+
+ # Strip invalid architectures so "fat" simulator / device frameworks work on device
+ if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
+ strip_invalid_archs "$binary"
+ fi
+
+ if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
+ # Move the stripped file into its final destination.
+ echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
+ rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
+ else
+ # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
+ touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
+ fi
+ fi
+}
+
+# Signs a framework with the provided identity
+code_sign_if_enabled() {
+ if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
+ # Use the current code_sign_identitiy
+ echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
+ local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
+
+ if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
+ code_sign_cmd="$code_sign_cmd &"
+ fi
+ echo "$code_sign_cmd"
+ eval "$code_sign_cmd"
+ fi
+}
+
+# Strip invalid architectures
+strip_invalid_archs() {
+ binary="$1"
+ # Get architectures for current target binary
+ binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
+ # Intersect them with the architectures we are building for
+ intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
+ # If there are no archs supported by this binary then warn the user
+ if [[ -z "$intersected_archs" ]]; then
+ echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
+ STRIP_BINARY_RETVAL=0
+ return
+ fi
+ stripped=""
+ for arch in $binary_archs; do
+ if ! [[ "${ARCHS}" == *"$arch"* ]]; then
+ # Strip non-valid architectures in-place
+ lipo -remove "$arch" -output "$binary" "$binary" || exit 1
+ stripped="$stripped $arch"
+ fi
+ done
+ if [[ "$stripped" ]]; then
+ echo "Stripped $binary of architectures:$stripped"
+ fi
+ STRIP_BINARY_RETVAL=1
+}
+
+if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
+ wait
+fi
--- /dev/null
+#!/bin/sh
+set -e
+set -u
+set -o pipefail
+
+if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
+ # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
+ # resources to, so exit 0 (signalling the script phase was successful).
+ exit 0
+fi
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+
+RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
+> "$RESOURCES_TO_COPY"
+
+XCASSET_FILES=()
+
+# This protects against multiple targets copying the same framework dependency at the same time. The solution
+# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
+RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
+
+case "${TARGETED_DEVICE_FAMILY:-}" in
+ 1,2)
+ TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
+ ;;
+ 1)
+ TARGET_DEVICE_ARGS="--target-device iphone"
+ ;;
+ 2)
+ TARGET_DEVICE_ARGS="--target-device ipad"
+ ;;
+ 3)
+ TARGET_DEVICE_ARGS="--target-device tv"
+ ;;
+ 4)
+ TARGET_DEVICE_ARGS="--target-device watch"
+ ;;
+ *)
+ TARGET_DEVICE_ARGS="--target-device mac"
+ ;;
+esac
+
+install_resource()
+{
+ if [[ "$1" = /* ]] ; then
+ RESOURCE_PATH="$1"
+ else
+ RESOURCE_PATH="${PODS_ROOT}/$1"
+ fi
+ if [[ ! -e "$RESOURCE_PATH" ]] ; then
+ cat << EOM
+error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
+EOM
+ exit 1
+ fi
+ case $RESOURCE_PATH in
+ *.storyboard)
+ echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
+ ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+ ;;
+ *.xib)
+ echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
+ ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
+ ;;
+ *.framework)
+ echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
+ mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+ echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
+ rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+ ;;
+ *.xcdatamodel)
+ echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
+ xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
+ ;;
+ *.xcdatamodeld)
+ echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
+ xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
+ ;;
+ *.xcmappingmodel)
+ echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
+ xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
+ ;;
+ *.xcassets)
+ ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
+ XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
+ ;;
+ *)
+ echo "$RESOURCE_PATH" || true
+ echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
+ ;;
+ esac
+}
+
+mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
+ mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+ rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+fi
+rm -f "$RESOURCES_TO_COPY"
+
+if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
+then
+ # Find all other xcassets (this unfortunately includes those of path pods and other targets).
+ OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
+ while read line; do
+ if [[ $line != "${PODS_ROOT}*" ]]; then
+ XCASSET_FILES+=("$line")
+ fi
+ done <<<"$OTHER_XCASSETS"
+
+ if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
+ printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
+ else
+ printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
+ fi
+fi
--- /dev/null
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+OTHER_LDFLAGS = $(inherited) -ObjC
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
+PODS_ROOT = ${SRCROOT}/Pods
--- /dev/null
+GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
+OTHER_LDFLAGS = $(inherited) -ObjC
+PODS_BUILD_DIR = ${BUILD_DIR}
+PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
+PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
+PODS_ROOT = ${SRCROOT}/Pods
};
objectVersion = 46;
objects = {
-
/* Begin PBXBuildFile section */
0207DA581B56EA530066E2B4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0207DA571B56EA530066E2B4 /* Images.xcassets */; };
0FBFC45D12B44FF79785B959 /* UIImage+CropScaleOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 281DF600F6B747808087E4FC /* UIImage+CropScaleOrientation.m */; };
9224D3CE70AE4072BBEB170D /* CDVLocalFilesystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A8DD2DDC8694A97A56F9FA7 /* CDVLocalFilesystem.m */; };
94868B10923A4508B06A4310 /* CDVAssetLibraryFilesystem.m in Sources */ = {isa = PBXBuildFile; fileRef = A719A69FD70D4CC9B8104FF6 /* CDVAssetLibraryFilesystem.m */; };
A42AE846FF7B482FB889AAEB /* QRScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8478FFD487C4004A1CEFCA8 /* QRScanner.swift */; };
+ A50EB04ADB24A5CBB680802F /* libPods-dlapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D992375F52889311A88544EF /* libPods-dlapp.a */; };
B69FF513D1EE4772AFF6050B /* Fingerprint.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2099240B64744E08C91C285 /* Fingerprint.swift */; };
B8EFB66D03A44372A240B05B /* CDVCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 80B448E71F8941268B78692C /* CDVCamera.m */; };
BC39BA77AF0D4F94BC27666A /* CDVDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = A50DE9801E5E4302A78D569C /* CDVDevice.m */; };
F46AE1B50D8B4A81B05D4100 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A673D8D8920E4086A9152FC4 /* Security.framework */; };
F939AD8D22BB769B006B371B /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F939AD8C22BB769B006B371B /* libsqlite3.0.tbd */; };
FDE92C386167415E8040F8AB /* AFURLResponseSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = FDEE8379D7A34C55A616F700 /* AFURLResponseSerialization.m */; };
+ 04347BD0ABAC4EE0B4CDDDB6 /* jcore-ios-2.1.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 444DBF371D8346D7BC7EE35D /* jcore-ios-2.1.1.a */; };
+ 3EBABAA2209349F6AF91DF03 /* JPushPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = CD3E9CB7CBA54989AB62BA7F /* JPushPlugin.m */; };
+ A54A9FED843144C887EA4286 /* AppDelegate+JPush.m in Sources */ = {isa = PBXBuildFile; fileRef = 91E044FC8377488C886C818B /* AppDelegate+JPush.m */; };
+ C04B4EC2FAAD4D328ABA0C95 /* jpush-ios-3.2.1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CCDEFB0C0632436FA86F0F31 /* jpush-ios-3.2.1.a */; };
+ 3BE6767AAFDC4926A08E6690 /* JPushConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = E9D260B7FB6C49A3AE6CD0DB /* JPushConfig.plist */; };
+ BFA0CF013EEC44F9B2C6FA6E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0162975BB3964038A51EDED4 /* CFNetwork.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 7EC1B4999B2E48C098BA1BBB /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C44E29C3B190445C98BBAB84 /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 432FFA418F2F4247BE9C8472 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1F790D5B00B4F178F835DE1 /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 7352A67D82B2499FBFFF8A2A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B080F410C164D6582A23E36 /* Foundation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ A15A414BEE7A48538C758317 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D5F2FFCAD8E4A4392B781A3 /* UIKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ D3E822CFC71546E191C10DA7 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 22DF35565BBA44B1980FFAF5 /* libz.tbd */; settings = {ATTRIBUTES = (Weak, ); }; };
+ CDD6F217CA274CF18EC146D3 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 048B6FC037E1479790969D83 /* AdSupport.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 77CDF61132F44B81B0064744 /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59D1F618C1ED464283B7B2E6 /* UserNotifications.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 3C00FC06B74E49CFBABD0CFF /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = CBD6EA74C612474DA862E146 /* libresolv.tbd */; settings = {ATTRIBUTES = (Weak, ); }; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
301BF534109A57CC0062928A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
- containerPortal = 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */;
+ containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = D2AAC07E0554694100DB518D;
remoteInfo = CordovaLib;
};
301BF550109A68C00062928A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
- containerPortal = 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */;
+ containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = D2AAC07D0554694100DB518D;
remoteInfo = CordovaLib;
};
907D8123214C687600058A10 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
- containerPortal = 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */;
+ containerPortal = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = C0C01EB21E3911D50056E6CB;
remoteInfo = Cordova;
28B91F31B6FD410AAF87BBDC /* CDVThemeableBrowser.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVThemeableBrowser.m; path = "cordova-plugin-themeablebrowser/CDVThemeableBrowser.m"; sourceTree = "<group>"; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
2F977C7D2E4448098AA27AE8 /* CDVAssetLibraryFilesystem.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVAssetLibraryFilesystem.h; path = "cordova-plugin-file/CDVAssetLibraryFilesystem.h"; sourceTree = "<group>"; };
- 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
+ 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; };
302D95EE14D2391D003F00A1 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
302D95EF14D2391D003F00A1 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
C2099240B64744E08C91C285 /* Fingerprint.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = Fingerprint.swift; path = "cordova-plugin-fingerprint-aio/Fingerprint.swift"; sourceTree = "<group>"; };
C8478FFD487C4004A1CEFCA8 /* QRScanner.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = QRScanner.swift; path = "cordova-plugin-qrscanner/QRScanner.swift"; sourceTree = "<group>"; };
D4DBE4512BAD4694B7EB5217 /* SDNetworkActivityIndicator.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = SDNetworkActivityIndicator.h; path = "cordova-plugin-advanced-http/SDNetworkActivityIndicator.h"; sourceTree = "<group>"; };
+ D992375F52889311A88544EF /* libPods-dlapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-dlapp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DBDBB5C64D17465C9452AF28 /* TextRequestSerializer.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = TextRequestSerializer.m; path = "cordova-plugin-advanced-http/TextRequestSerializer.m"; sourceTree = "<group>"; };
DD3651F245114E52ABEB9060 /* CDVFile.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = CDVFile.m; path = "cordova-plugin-file/CDVFile.m"; sourceTree = "<group>"; };
DE50527E757F47D08F4E076C /* CDVFile.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = CDVFile.h; path = "cordova-plugin-file/CDVFile.h"; sourceTree = "<group>"; };
F939AD8C22BB769B006B371B /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
FCC7E279D80D4FB9BCF2530A /* Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "Bridging-Header.h"; path = "cordova-plugin-fingerprint-aio/Bridging-Header.h"; sourceTree = "<group>"; };
FDEE8379D7A34C55A616F700 /* AFURLResponseSerialization.m */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.objc; name = AFURLResponseSerialization.m; path = "cordova-plugin-advanced-http/AFURLResponseSerialization.m"; sourceTree = "<group>"; };
+ 444DBF371D8346D7BC7EE35D /* jcore-ios-2.1.1.a */ = {isa = PBXFileReference; name = "jcore-ios-2.1.1.a"; path = "dlapp/Plugins/cordova-plugin-jcore/jcore-ios-2.1.1.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+ CD3E9CB7CBA54989AB62BA7F /* JPushPlugin.m */ = {isa = PBXFileReference; name = "JPushPlugin.m"; path = "jpush-phonegap-plugin/JPushPlugin.m"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; explicitFileType = undefined; includeInIndex = 0; };
+ 91E044FC8377488C886C818B /* AppDelegate+JPush.m */ = {isa = PBXFileReference; name = "AppDelegate+JPush.m"; path = "jpush-phonegap-plugin/AppDelegate+JPush.m"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; explicitFileType = undefined; includeInIndex = 0; };
+ CCDEFB0C0632436FA86F0F31 /* jpush-ios-3.2.1.a */ = {isa = PBXFileReference; name = "jpush-ios-3.2.1.a"; path = "dlapp/Plugins/jpush-phonegap-plugin/jpush-ios-3.2.1.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
+ FC8EA7F3637547AD8BC62127 /* JPushDefine.h */ = {isa = PBXFileReference; name = "JPushDefine.h"; path = "jpush-phonegap-plugin/JPushDefine.h"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; explicitFileType = undefined; includeInIndex = 0; };
+ 3291AEB63DCC45B58959915F /* JPushPlugin.h */ = {isa = PBXFileReference; name = "JPushPlugin.h"; path = "jpush-phonegap-plugin/JPushPlugin.h"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; explicitFileType = undefined; includeInIndex = 0; };
+ 0EFE153A83734473AE4D0E4C /* AppDelegate+JPush.h */ = {isa = PBXFileReference; name = "AppDelegate+JPush.h"; path = "jpush-phonegap-plugin/AppDelegate+JPush.h"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; explicitFileType = undefined; includeInIndex = 0; };
+ A32F7333BFEB461B9C84F6E5 /* JPUSHService.h */ = {isa = PBXFileReference; name = "JPUSHService.h"; path = "jpush-phonegap-plugin/JPUSHService.h"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; explicitFileType = undefined; includeInIndex = 0; };
+ E9D260B7FB6C49A3AE6CD0DB /* JPushConfig.plist */ = {isa = PBXFileReference; name = "JPushConfig.plist"; path = "JPushConfig.plist"; sourceTree = "<group>"; fileEncoding = 4; lastKnownFileType = text.plist.xml; explicitFileType = undefined; includeInIndex = 0; };
+ 0162975BB3964038A51EDED4 /* CFNetwork.framework */ = {isa = PBXFileReference; name = "CFNetwork.framework"; path = "System/Library/Frameworks/CFNetwork.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ C44E29C3B190445C98BBAB84 /* CoreFoundation.framework */ = {isa = PBXFileReference; name = "CoreFoundation.framework"; path = "System/Library/Frameworks/CoreFoundation.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ B1F790D5B00B4F178F835DE1 /* CoreTelephony.framework */ = {isa = PBXFileReference; name = "CoreTelephony.framework"; path = "System/Library/Frameworks/CoreTelephony.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ 9B080F410C164D6582A23E36 /* Foundation.framework */ = {isa = PBXFileReference; name = "Foundation.framework"; path = "System/Library/Frameworks/Foundation.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ 6D5F2FFCAD8E4A4392B781A3 /* UIKit.framework */ = {isa = PBXFileReference; name = "UIKit.framework"; path = "System/Library/Frameworks/UIKit.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ 22DF35565BBA44B1980FFAF5 /* libz.tbd */ = {isa = PBXFileReference; name = "libz.tbd"; path = "usr/lib/libz.tbd"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = sourcecode.text-based-dylib-definition; explicitFileType = undefined; includeInIndex = 0; };
+ 048B6FC037E1479790969D83 /* AdSupport.framework */ = {isa = PBXFileReference; name = "AdSupport.framework"; path = "System/Library/Frameworks/AdSupport.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ 59D1F618C1ED464283B7B2E6 /* UserNotifications.framework */ = {isa = PBXFileReference; name = "UserNotifications.framework"; path = "System/Library/Frameworks/UserNotifications.framework"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = wrapper.framework; explicitFileType = undefined; includeInIndex = 0; };
+ CBD6EA74C612474DA862E146 /* libresolv.tbd */ = {isa = PBXFileReference; name = "libresolv.tbd"; path = "usr/lib/libresolv.tbd"; sourceTree = SDKROOT; fileEncoding = undefined; lastKnownFileType = sourcecode.text-based-dylib-definition; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7D8430D010A848FBBA5FB7ED /* ImageIO.framework in Frameworks */,
D2F2072984AE43BCBD0A430D /* CoreLocation.framework in Frameworks */,
74A56CC7F6724870ABD136F2 /* AVFoundation.framework in Frameworks */,
+ A50EB04ADB24A5CBB680802F /* libPods-dlapp.a in Frameworks */,
+ 04347BD0ABAC4EE0B4CDDDB6 /* jcore-ios-2.1.1.a in Frameworks */,
+ C04B4EC2FAAD4D328ABA0C95 /* jpush-ios-3.2.1.a in Frameworks */,
+ BFA0CF013EEC44F9B2C6FA6E /* CFNetwork.framework in Frameworks */,
+ 7EC1B4999B2E48C098BA1BBB /* CoreFoundation.framework in Frameworks */,
+ 432FFA418F2F4247BE9C8472 /* CoreTelephony.framework in Frameworks */,
+ 7352A67D82B2499FBFFF8A2A /* Foundation.framework in Frameworks */,
+ A15A414BEE7A48538C758317 /* UIKit.framework in Frameworks */,
+ D3E822CFC71546E191C10DA7 /* libz.tbd in Frameworks */,
+ CDD6F217CA274CF18EC146D3 /* AdSupport.framework in Frameworks */,
+ 77CDF61132F44B81B0064744 /* UserNotifications.framework in Frameworks */,
+ 3C00FC06B74E49CFBABD0CFF /* libresolv.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
name = Products;
sourceTree = "<group>";
};
- 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+ 29B97314FDCFA39411CA2CEA = {
isa = PBXGroup;
children = (
EB87FDF41871DAF40020F90C /* config.xml */,
EB87FDF31871DA8E0020F90C /* www */,
EB87FDF11871DA420020F90C /* Staging */,
- 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */,
+ 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */,
080E96DDFE201D6D7F000001 /* Classes */,
307C750510C5A3420062BCA9 /* Plugins */,
29B97315FDCFA39411CA2CEA /* Other Sources */,
29B97317FDCFA39411CA2CEA /* Resources */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
19C28FACFE9D520D11CA2CBB /* Products */,
+ BC4A1507117AEF25CBA069D3 /* Pods */,
);
name = CustomTemplate;
sourceTree = "<group>";
0207DA571B56EA530066E2B4 /* Images.xcassets */,
3047A50E1AB8057F00498E2A /* config */,
8D1107310486CEB800E47090 /* dlapp-Info.plist */,
+ E9D260B7FB6C49A3AE6CD0DB /* JPushConfig.plist */,
);
name = Resources;
path = dlapp/Resources;
5192EB17EA164DFD80D433E4 /* ImageIO.framework */,
1D1F25845F964D87B880BFA9 /* CoreLocation.framework */,
11A34CB026314A2AA98A0044 /* AVFoundation.framework */,
+ D992375F52889311A88544EF /* libPods-dlapp.a */,
+ 444DBF371D8346D7BC7EE35D /* jcore-ios-2.1.1.a */,
+ CCDEFB0C0632436FA86F0F31 /* jpush-ios-3.2.1.a */,
+ 0162975BB3964038A51EDED4 /* CFNetwork.framework */,
+ C44E29C3B190445C98BBAB84 /* CoreFoundation.framework */,
+ B1F790D5B00B4F178F835DE1 /* CoreTelephony.framework */,
+ 9B080F410C164D6582A23E36 /* Foundation.framework */,
+ 6D5F2FFCAD8E4A4392B781A3 /* UIKit.framework */,
+ 22DF35565BBA44B1980FFAF5 /* libz.tbd */,
+ 048B6FC037E1479790969D83 /* AdSupport.framework */,
+ 59D1F618C1ED464283B7B2E6 /* UserNotifications.framework */,
+ CBD6EA74C612474DA862E146 /* libresolv.tbd */,
);
name = Frameworks;
sourceTree = "<group>";
265BE52D975B49ACA2F7B3FE /* CDVDevice.h */,
28B91F31B6FD410AAF87BBDC /* CDVThemeableBrowser.m */,
EF1A4FA720C24397A32AF09C /* CDVThemeableBrowser.h */,
+ CD3E9CB7CBA54989AB62BA7F /* JPushPlugin.m */,
+ 91E044FC8377488C886C818B /* AppDelegate+JPush.m */,
+ FC8EA7F3637547AD8BC62127 /* JPushDefine.h */,
+ 3291AEB63DCC45B58959915F /* JPushPlugin.h */,
+ 0EFE153A83734473AE4D0E4C /* AppDelegate+JPush.h */,
+ A32F7333BFEB461B9C84F6E5 /* JPUSHService.h */,
);
name = Plugins;
path = dlapp/Plugins;
sourceTree = SOURCE_ROOT;
};
+ BC4A1507117AEF25CBA069D3 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Pods;
+ sourceTree = "<group>";
+ };
EB87FDF11871DA420020F90C /* Staging */ = {
isa = PBXGroup;
children = (
isa = PBXNativeTarget;
buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "dlapp" */;
buildPhases = (
+ CE3CFE251273EDBCFA429761 /* [CP] Check Pods Manifest.lock */,
304B58A110DAC018002A0835 /* Copy www directory */,
1D60588D0D05DD3D006BFB54 /* Resources */,
1D60588E0D05DD3D006BFB54 /* Sources */,
English,
en,
);
- mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+ mainGroup = 29B97314FDCFA39411CA2CEA;
+ productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 301BF52E109A57CC0062928A /* Products */;
- ProjectRef = 301BF52D109A57CC0062928A /* CordovaLib/CordovaLib.xcodeproj */;
+ ProjectRef = 301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */;
},
);
projectRoot = "";
files = (
302D95F214D2391D003F00A1 /* MainViewController.xib in Resources */,
0207DA581B56EA530066E2B4 /* Images.xcassets in Resources */,
+ 3BE6767AAFDC4926A08E6690 /* JPushConfig.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
shellScript = "\"$SRCROOT/dlapp/Scripts/copy-www-build-step.sh\"";
showEnvVarsInLog = 0;
};
+ CE3CFE251273EDBCFA429761 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-dlapp-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
6FB343627AC8409CB2AA79B7 /* CDVInAppBrowser.m in Sources */,
BC39BA77AF0D4F94BC27666A /* CDVDevice.m in Sources */,
4F83621E48F143429B20FB3A /* CDVThemeableBrowser.m in Sources */,
+ 3EBABAA2209349F6AF91DF03 /* JPushPlugin.m in Sources */,
+ A54A9FED843144C887EA4286 /* AppDelegate+JPush.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-jcore\"",
+ "\"$(SRCROOT)/$(TARGET_NAME)/Plugins/jpush-phonegap-plugin\"",
+ );
};
name = Debug;
};
SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/$(PROJECT_NAME)/Bridging-Header.h";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "\"$(SRCROOT)/$(TARGET_NAME)/Plugins/cordova-plugin-jcore\"",
+ "\"$(SRCROOT)/$(TARGET_NAME)/Plugins/jpush-phonegap-plugin\"",
+ );
};
name = Release;
};
<FileRef
location = "group:dlapp.xcodeproj">
</FileRef>
+ <FileRef
+ location = "group:Pods/Pods.xcodeproj">
+ </FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
- <dict>
- </dict>
-</plist>
+<dict>
+ <key>aps-environment</key>
+ <string>development</string>
+</dict>
+</plist>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
- <dict>
- </dict>
-</plist>
+<dict>
+ <key>aps-environment</key>
+ <string>production</string>
+</dict>
+</plist>
\ No newline at end of file
--- /dev/null
+//\r
+// AppDelegate+JPush.h\r
+// delegateExtention\r
+//\r
+// Created by 张庆贺 on 15/8/3.\r
+// Copyright (c) 2015年 JPush. All rights reserved.\r
+//\r
+\r
+#import "AppDelegate.h"\r
+#import <UserNotifications/UserNotifications.h>\r
+#import "JPUSHService.h"\r
+\r
+@interface AppDelegate (JPush) <JPUSHRegisterDelegate>\r
+-(void)registerForRemoteNotification;\r
+-(void)startJPushSDK;\r
+@end\r
--- /dev/null
+//
+// AppDelegate+JPush.m
+// delegateExtention
+//
+// Created by 张庆贺 on 15/8/3.
+// Copyright (c) 2015年 JPush. All rights reserved.
+//
+
+#import "AppDelegate+JPush.h"
+#import "JPushPlugin.h"
+#import <objc/runtime.h>
+#import <AdSupport/AdSupport.h>
+#import <UserNotifications/UserNotifications.h>
+#import "JPushDefine.h"
+
+@implementation AppDelegate (JPush)
+
++(void)load{
+ Method origin1;
+ Method swizzle1;
+ origin1 = class_getInstanceMethod([self class],@selector(init));
+ swizzle1 = class_getInstanceMethod([self class], @selector(init_plus));
+ method_exchangeImplementations(origin1, swizzle1);
+}
+
+-(instancetype)init_plus{
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidLaunch:) name:UIApplicationDidFinishLaunchingNotification object:nil];
+ return [self init_plus];
+}
+
+NSDictionary *_launchOptions;
+-(void)applicationDidLaunch:(NSNotification *)notification{
+
+ if (!_jpushEventCache) {
+ _jpushEventCache = @{}.mutableCopy;
+ }
+
+ [JPUSHService registrationIDCompletionHandler:^(int resCode, NSString *registrationID) {
+ NSDictionary *event = @{@"registrationId": registrationID?:@""};
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_receiveRegistrationId jsString:[event toJsonString]];
+ }];
+
+ if (notification != nil &&
+ [[UIDevice currentDevice].systemVersion floatValue] < 10.0) {// iOS 10 以后通过 openNotification 这个回调触发事件。
+ if (notification.userInfo) {
+
+ if ([notification.userInfo valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification
+ jsString:[[self jpushFormatAPNSDic: notification.userInfo[UIApplicationLaunchOptionsRemoteNotificationKey]] toJsonString]];
+ }
+
+ if ([notification.userInfo valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]) {
+ UILocalNotification *localNotification = [notification.userInfo valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
+ NSMutableDictionary *localNotificationEvent = @{}.mutableCopy;
+ localNotificationEvent[@"content"] = localNotification.alertBody;
+ localNotificationEvent[@"badge"] = @(localNotification.applicationIconBadgeNumber);
+ localNotificationEvent[@"extras"] = localNotification.userInfo;
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification jsString:[localNotificationEvent toJsonString]];
+ }
+ }
+ }
+
+ [JPUSHService setDebugMode];
+
+ NSString *plistPath = [[NSBundle mainBundle] pathForResource:JPushConfig_FileName ofType:@"plist"];
+ NSMutableDictionary *plistData = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+ NSNumber *delay = [plistData valueForKey:JPushConfig_Delay];
+
+ _launchOptions = notification.userInfo;
+
+ if (![delay boolValue]) {
+ [self startJPushSDK];
+ }
+}
+
+-(void)startJPushSDK{
+ [self registerForRemoteNotification];
+ [JPushPlugin setupJPushSDK:_launchOptions];
+}
+
+- (void)jpushSDKDidLoginNotification {
+ NSDictionary *event = @{@"registrationId": JPUSHService.registrationID};
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_receiveRegistrationId jsString:[event toJsonString]];
+}
+
+- (NSMutableDictionary *)jpushFormatAPNSDic:(NSDictionary *)dic {
+ NSMutableDictionary *extras = @{}.mutableCopy;
+ for (NSString *key in dic) {
+ if([key isEqualToString:@"_j_business"] ||
+ [key isEqualToString:@"_j_msgid"] ||
+ [key isEqualToString:@"_j_uid"] ||
+ [key isEqualToString:@"actionIdentifier"] ||
+ [key isEqualToString:@"aps"]) {
+ continue;
+ }
+ extras[key] = dic[key];
+ }
+ NSMutableDictionary *formatDic = dic.mutableCopy;
+ formatDic[@"extras"] = extras;
+ return formatDic;
+}
+
+-(void)registerForRemoteNotification{
+ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
+#ifdef NSFoundationVersionNumber_iOS_9_x_Max
+ JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
+ entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
+ [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
+#endif
+ }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
+ //可以添加自定义categories
+ [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
+ UIUserNotificationTypeSound |
+ UIUserNotificationTypeAlert)
+ categories:nil];
+ } else if([[UIDevice currentDevice].systemVersion floatValue] < 8.0){
+ //categories 必须为nil
+ [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
+ UIRemoteNotificationTypeSound |
+ UIRemoteNotificationTypeAlert)
+ categories:nil];
+ }
+}
+
+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+ [JPUSHService registerDeviceToken:deviceToken];
+}
+
+-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
+ [JPUSHService handleRemoteNotification:userInfo];
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveNotification jsString:[userInfo toJsonString]];
+}
+
+-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
+ [JPUSHService handleRemoteNotification:userInfo];
+ NSString *eventName;
+ switch ([UIApplication sharedApplication].applicationState) {
+ case UIApplicationStateBackground:
+ eventName = JPushDocumentEvent_BackgroundNotification;
+ break;
+ default:
+ eventName = JPushDocumentEvent_ReceiveNotification;
+ break;
+ }
+
+ [JPushPlugin fireDocumentEvent:eventName jsString:[[self jpushFormatAPNSDic:userInfo] toJsonString]];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completionHandler(UIBackgroundFetchResultNewData);
+ });
+}
+
+-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler{
+ NSMutableDictionary *userInfo = @{}.mutableCopy;
+
+ if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
+ userInfo = [self jpushFormatAPNSDic:notification.request.content.userInfo];
+ } else {
+ UNNotificationContent *content = notification.request.content;
+ userInfo[@"content"] = content.body;
+ userInfo[@"badge"] = content.badge;
+ userInfo[@"extras"] = content.userInfo;
+ userInfo[@"identifier"] = notification.request.identifier;
+ }
+
+ completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
+
+ if ([userInfo[@"aps"][@"content-available"] isEqualToNumber:@(1)]) {// content-available 当用户开启后台推送是,防止触发两次事件
+ return;
+ }
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveNotification jsString:[userInfo toJsonString]];
+
+}
+
+-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
+ UNNotification *notification = response.notification;
+ NSMutableDictionary *userInfo = @{}.mutableCopy;
+
+ if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
+ userInfo = [self jpushFormatAPNSDic:notification.request.content.userInfo];
+ } else {
+ UNNotificationContent *content = notification.request.content;
+ userInfo[@"content"] = content.body;
+ userInfo[@"badge"] = content.badge;
+ userInfo[@"extras"] = content.userInfo;
+ userInfo[@"identifier"] = notification.request.identifier;
+ }
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification jsString:[userInfo toJsonString]];
+ completionHandler();
+}
+
+- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
+ NSMutableDictionary *localNotificationEvent = @{}.mutableCopy;
+ localNotificationEvent[@"content"] = notification.alertBody;
+ localNotificationEvent[@"badge"] = @(notification.applicationIconBadgeNumber);
+ localNotificationEvent[@"extras"] = notification.userInfo;
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:JPushDocumentEvent_ReceiveLocalNotification object:localNotificationEvent];
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // [application setApplicationIconBadgeNumber:0];
+ // [application cancelAllLocalNotifications];
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
+}
+
+@end
--- /dev/null
+/*
+ * | | | | \ \ / / | | | | / _______|
+ * | |____| | \ \/ / | |____| | / /
+ * | |____| | \ / | |____| | | | _____
+ * | | | | / \ | | | | | | |____ |
+ * | | | | / /\ \ | | | | \ \______| |
+ * | | | | /_/ \_\ | | | | \_________|
+ *
+ * Copyright (c) 2011 ~ 2017 Shenzhen HXHG. All rights reserved.
+ */
+
+#define JPUSH_VERSION_NUMBER 3.2.1
+
+#import <Foundation/Foundation.h>
+
+@class CLRegion;
+@class UILocalNotification;
+@class CLLocation;
+@class UNNotificationCategory;
+@class UNNotificationSettings;
+@class UNNotificationRequest;
+@class UNNotification;
+@protocol JPUSHRegisterDelegate;
+@protocol JPUSHGeofenceDelegate;
+
+typedef void (^JPUSHTagsOperationCompletion)(NSInteger iResCode, NSSet *iTags, NSInteger seq);
+typedef void (^JPUSHTagValidOperationCompletion)(NSInteger iResCode, NSSet *iTags, NSInteger seq, BOOL isBind);
+typedef void (^JPUSHAliasOperationCompletion)(NSInteger iResCode, NSString *iAlias, NSInteger seq);
+
+extern NSString *const kJPFNetworkIsConnectingNotification; // 正在连接中
+extern NSString *const kJPFNetworkDidSetupNotification; // 建立连接
+extern NSString *const kJPFNetworkDidCloseNotification; // 关闭连接
+extern NSString *const kJPFNetworkDidRegisterNotification; // 注册成功
+extern NSString *const kJPFNetworkFailedRegisterNotification; //注册失败
+extern NSString *const kJPFNetworkDidLoginNotification; // 登录成功
+extern NSString *const kJPFNetworkDidReceiveMessageNotification; // 收到消息(非APNS)
+extern NSString *const kJPFServiceErrorNotification; // 错误提示
+
+typedef NS_OPTIONS(NSUInteger, JPAuthorizationOptions) {
+ JPAuthorizationOptionNone = 0, // the application may not present any UI upon a notification being received
+ JPAuthorizationOptionBadge = (1 << 0), // the application may badge its icon upon a notification being received
+ JPAuthorizationOptionSound = (1 << 1), // the application may play a sound upon a notification being received
+ JPAuthorizationOptionAlert = (1 << 2), // the application may display an alert upon a notification being received
+ JPAuthorizationOptionCarPlay = (1 << 3), // The ability to display notifications in a CarPlay environment.
+ JPAuthorizationOptionCriticalAlert NS_AVAILABLE_IOS(12.0) = (1 << 4) , //The ability to play sounds for critical alerts.
+ JPAuthorizationOptionProvidesAppNotificationSettings NS_AVAILABLE_IOS(12.0) = (1 << 5) , //An option indicating the system should display a button for in-app notification settings.
+ JPAuthorizationOptionProvisional NS_AVAILABLE_IOS(12.0) = (1 << 6) , //The ability to post noninterrupting notifications provisionally to the Notification Center.
+
+};
+
+/*!
+ * 通知注册实体类
+ */
+@interface JPUSHRegisterEntity : NSObject
+
+/*!
+ * 支持的类型
+ * badge,sound,alert
+ */
+@property (nonatomic, assign) NSInteger types;
+/*!
+ * 注入的类别
+ * iOS10 UNNotificationCategory
+ * iOS8-iOS9 UIUserNotificationCategory
+ */
+@property (nonatomic, strong) NSSet *categories;
+@end
+
+/*!
+ * 进行删除、查找推送实体类
+ */
+@interface JPushNotificationIdentifier : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSArray<NSString *> *identifiers; // 推送的标识数组
+@property (nonatomic, copy) UILocalNotification *notificationObj NS_DEPRECATED_IOS(4_0, 10_0); // iOS10以下可以传UILocalNotification对象数据,iOS10以上无效
+@property (nonatomic, assign) BOOL delivered NS_AVAILABLE_IOS(10_0); // 在通知中心显示的或待推送的标志,默认为NO,YES表示在通知中心显示的,NO表示待推送的
+@property (nonatomic, copy) void (^findCompletionHandler)(NSArray *results); // 用于查询回调,调用[findNotification:]方法前必须设置,results为返回相应对象数组,iOS10以下返回UILocalNotification对象数组;iOS10以上根据delivered传入值返回UNNotification或UNNotificationRequest对象数组(delivered传入YES,则返回UNNotification对象数组,否则返回UNNotificationRequest对象数组)
+
+@end
+
+/*!
+ * 推送通知声音实体类
+ * iOS10以上有效
+ */
+@interface JPushNotificationSound : NSObject <NSCopying, NSCoding>
+@property (nonatomic, copy) NSString *soundName; //普通通知铃声
+@property (nonatomic, copy) NSString *criticalSoundName NS_AVAILABLE_IOS(12.0); //警告通知铃声
+@property (nonatomic, assign) float criticalSoundVolume NS_AVAILABLE_IOS(12.0); //警告通知铃声音量,有效值在0~1之间,默认为1
+@end
+
+
+/*!
+ * 推送内容实体类
+ */
+@interface JPushNotificationContent : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSString *title; // 推送标题
+@property (nonatomic, copy) NSString *subtitle; // 推送副标题
+@property (nonatomic, copy) NSString *body; // 推送内容
+@property (nonatomic, copy) NSNumber *badge; // 角标的数字。如果不需要改变角标传@(-1)
+@property (nonatomic, copy) NSString *action NS_DEPRECATED_IOS(8_0, 10_0); // 弹框的按钮显示的内容(IOS 8默认为"打开", 其他默认为"启动",iOS10以上无效)
+@property (nonatomic, copy) NSString *categoryIdentifier; // 行为分类标识
+@property (nonatomic, copy) NSDictionary *userInfo; // 本地推送时可以设置userInfo来增加附加信息,远程推送时设置的payload推送内容作为此userInfo
+@property (nonatomic, copy) NSString *sound; // 声音名称,不设置则为默认声音
+@property (nonatomic, copy) JPushNotificationSound *soundSetting NS_AVAILABLE_IOS(10.0); //推送声音实体
+@property (nonatomic, copy) NSArray *attachments NS_AVAILABLE_IOS(10_0); // 附件,iOS10以上有效,需要传入UNNotificationAttachment对象数组类型
+@property (nonatomic, copy) NSString *threadIdentifier NS_AVAILABLE_IOS(10_0); // 线程或与推送请求相关对话的标识,iOS10以上有效,可用来对推送进行分组
+@property (nonatomic, copy) NSString *launchImageName NS_AVAILABLE_IOS(10_0); // 启动图片名,iOS10以上有效,从推送启动时将会用到
+@property (nonatomic, copy) NSString *summaryArgument NS_AVAILABLE_IOS(12.0); //插入到通知摘要中的部分参数。iOS12以上有效。
+@property (nonatomic, assign) NSUInteger summaryArgumentCount NS_AVAILABLE_IOS(12.0); //插入到通知摘要中的项目数。iOS12以上有效。
+
+@end
+
+
+/*!
+ * 推送触发方式实体类
+ * 注:dateComponents、timeInterval、region在iOS10以上可选择其中一个参数传入有效值,如果同时传入值会根据优先级I、II、III使其中一种触发方式生效,fireDate为iOS10以下根据时间触发时须传入的参数
+ */
+@interface JPushNotificationTrigger : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, assign) BOOL repeat; // 设置是否重复,默认为NO
+@property (nonatomic, copy) NSDate *fireDate NS_DEPRECATED_IOS(2_0, 10_0); // 用来设置触发推送的时间,iOS10以上无效
+@property (nonatomic, copy) CLRegion *region NS_AVAILABLE_IOS(8_0); // 用来设置触发推送的位置,iOS8以上有效,iOS10以上优先级为I,应用需要有允许使用定位的授权
+@property (nonatomic, copy) NSDateComponents *dateComponents NS_AVAILABLE_IOS(10_0); // 用来设置触发推送的日期时间,iOS10以上有效,优先级为II
+@property (nonatomic, assign) NSTimeInterval timeInterval NS_AVAILABLE_IOS(10_0); // 用来设置触发推送的时间,iOS10以上有效,优先级为III
+
+@end
+
+/*!
+ * 注册或更新推送实体类
+ */
+@interface JPushNotificationRequest : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSString *requestIdentifier; // 推送请求标识
+@property (nonatomic, copy) JPushNotificationContent *content; // 设置推送的具体内容
+@property (nonatomic, copy) JPushNotificationTrigger *trigger; // 设置推送的触发方式
+@property (nonatomic, copy) void (^completionHandler)(id result); // 注册或更新推送成功回调,iOS10以上成功则result为UNNotificationRequest对象,失败则result为nil;iOS10以下成功result为UILocalNotification对象,失败则result为nil
+
+@end
+
+/*!
+ * JPush 核心头文件
+ */
+@interface JPUSHService : NSObject
+
+
+///----------------------------------------------------
+/// @name Setup 启动相关
+///----------------------------------------------------
+
+
+/*!
+ * @abstract 启动SDK
+ *
+ * @param launchingOption 启动参数.
+ * @param appKey 一个JPush 应用必须的,唯一的标识. 请参考 JPush 相关说明文档来获取这个标识.
+ * @param channel 发布渠道. 可选.
+ * @param isProduction 是否生产环境. 如果为开发状态,设置为 NO; 如果为生产状态,应改为 YES.
+ * App 证书环境取决于profile provision的配置,此处建议与证书环境保持一致.
+ *
+ * @discussion 提供SDK启动必须的参数, 来启动 SDK.
+ * 此接口必须在 App 启动时调用, 否则 JPush SDK 将无法正常工作.
+ */
++ (void)setupWithOption:(NSDictionary *)launchingOption
+ appKey:(NSString *)appKey
+ channel:(NSString *)channel
+ apsForProduction:(BOOL)isProduction;
+
+/*!
+ * @abstract 启动SDK
+ *
+ * @param launchingOption 启动参数.
+ * @param appKey 一个JPush 应用必须的,唯一的标识. 请参考 JPush 相关说明文档来获取这个标识.
+ * @param channel 发布渠道. 可选.
+ * @param isProduction 是否生产环境. 如果为开发状态,设置为 NO; 如果为生产状态,应改为 YES.
+ * App 证书环境取决于profile provision的配置,此处建议与证书环境保持一致.
+ * @param advertisingId 广告标识符(IDFA) 如果不需要使用IDFA,传nil.
+ *
+ * @discussion 提供SDK启动必须的参数, 来启动 SDK.
+ * 此接口必须在 App 启动时调用, 否则 JPush SDK 将无法正常工作.
+ */
++ (void)setupWithOption:(NSDictionary *)launchingOption
+ appKey:(NSString *)appKey
+ channel:(NSString *)channel
+ apsForProduction:(BOOL)isProduction
+ advertisingIdentifier:(NSString *)advertisingId;
+
+
+///----------------------------------------------------
+/// @name APNs about 通知相关
+///----------------------------------------------------
+
+/*!
+ * @abstract 注册要处理的远程通知类型
+ *
+ * @param types 通知类型
+ * @param categories 类别组
+ *
+ */
++ (void)registerForRemoteNotificationTypes:(NSUInteger)types
+ categories:(NSSet *)categories;
+/*!
+ * @abstract 新版本的注册方法(兼容iOS10)
+ *
+ * @param config 注册通知配置
+ * @param delegate 代理
+ *
+ */
++ (void)registerForRemoteNotificationConfig:(JPUSHRegisterEntity *)config delegate:(id<JPUSHRegisterDelegate>)delegate;
+
+
++ (void)registerDeviceToken:(NSData *)deviceToken;
+
+
+/*!
+ * @abstract 处理收到的 APNs 消息
+ */
++ (void)handleRemoteNotification:(NSDictionary *)remoteInfo;
+
+/*!
+ * Tags操作接口
+ * 支持增加/覆盖/删除/清空/查询操作
+ * 详情请参考文档:https://docs.jiguang.cn/jpush/client/iOS/ios_api/)
+ */
+
+/**
+ 增加tags
+
+ @param tags 需要增加的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)addTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 覆盖tags
+ 调用该接口会覆盖用户所有的tags
+
+ @param tags 需要设置的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)setTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 删除指定tags
+
+ @param tags 需要删除的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)deleteTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 清空所有tags
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)cleanTags:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 查询全部tags
+
+ @param completion 响应回调,请在回调中获取查询结果
+ @param seq 请求序列号
+ */
++ (void)getAllTags:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 验证tag是否绑定
+
+ @param completion 响应回调,回调中查看是否绑定
+ @param seq 请求序列号
+ */
++ (void)validTag:(NSString *)tag
+ completion:(JPUSHTagValidOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 设置Alias
+
+ @param alias 需要设置的alias
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)setAlias:(NSString *)alias
+ completion:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 删除alias
+
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)deleteAlias:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 查询当前alias
+
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)getAlias:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+
+/*!
+ * @abstract 过滤掉无效的 tags
+ *
+ * @discussion 如果 tags 数量超过限制数量, 则返回靠前的有效的 tags.
+ * 建议设置 tags 前用此接口校验. SDK 内部也会基于此接口来做过滤.
+ */
++ (NSSet *)filterValidTags:(NSSet *)tags;
+
+///----------------------------------------------------
+/// @name Stats 统计功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 开始记录页面停留
+ *
+ * @param pageName 页面名称
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)startLogPageView:(NSString *)pageName __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 停止记录页面停留
+ *
+ * @param pageName 页面
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)stopLogPageView:(NSString *)pageName __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 直接上报在页面的停留时间
+ *
+ * @param pageName 页面
+ * @param seconds 停留的秒数
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)beginLogPageView:(NSString *)pageName duration:(int)seconds __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 开启Crash日志收集
+ *
+ * @discussion 默认是关闭状态.
+ */
++ (void)crashLogON;
+
+/*!
+ * @abstract 地理位置上报
+ *
+ * @param latitude 纬度.
+ * @param longitude 经度.
+ *
+ */
++ (void)setLatitude:(double)latitude longitude:(double)longitude;
+
+/*!
+ * @abstract 地理位置上报
+ *
+ * @param location 直接传递 CLLocation * 型的地理信息
+ *
+ * @discussion 需要链接 CoreLocation.framework 并且 #import <CoreLocation/CoreLocation.h>
+ */
++ (void)setLocation:(CLLocation *)location;
+
+/**
+ 设置地理围栏的最大个数
+ 默认值为 10 ,iOS系统默认地理围栏最大个数为20
+ @param count 个数 count
+ */
++ (void)setGeofenecMaxCount:(NSInteger)count;
+/**
+ 注册地理围栏的代理
+
+ @param delegate 代理
+ @param launchOptions app启动完成是收到的字段参数
+ */
++ (void)registerLbsGeofenceDelegate:(id<JPUSHGeofenceDelegate>)delegate withLaunchOptions:(NSDictionary *)launchOptions;
+
+/**
+ 删除地理围栏
+
+ @param geofenceId 地理围栏id
+ */
++ (void)removeGeofenceWithIdentifier:(NSString *)geofenceId;
+
+///----------------------------------------------------
+/// @name Local Notification 本地通知
+///----------------------------------------------------
+/*!
+ * @abstract 注册或更新推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param request JPushNotificationRequest类型,设置推送的属性,设置已有推送的request.requestIdentifier即更新已有的推送,否则为注册新推送,更新推送仅仅在iOS10以上有效,结果通过request.completionHandler返回
+ * @discussion 旧的注册本地推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)addNotification:(JPushNotificationRequest *)request;
+
+/*!
+ * @abstract 移除推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param identifier JPushNotificationIdentifier类型,iOS10以上identifier设置为nil,则移除所有在通知中心显示推送和待推送请求,也可以通过设置identifier.delivered和identifier.identifiers来移除相应在通知中心显示推送或待推送请求,identifier.identifiers如果设置为nil或空数组则移除相应标志下所有在通知中心显示推送或待推送请求;iOS10以下identifier设置为nil,则移除所有推送,identifier.delivered属性无效,另外可以通过identifier.notificationObj传入特定推送对象来移除此推送。
+ * @discussion 旧的所有删除推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)removeNotification:(JPushNotificationIdentifier *)identifier;
+
+/*!
+ * @abstract 查找推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param identifier JPushNotificationIdentifier类型,iOS10以上可以通过设置identifier.delivered和identifier.identifiers来查找相应在通知中心显示推送或待推送请求,identifier.identifiers如果设置为nil或空数组则返回相应标志下所有在通知中心显示推送或待推送请求;iOS10以下identifier.delivered属性无效,identifier.identifiers如果设置nil或空数组则返回所有未触发的推送。须要设置identifier.findCompletionHandler回调才能得到查找结果,通过(NSArray *results)返回相应对象数组。
+ * @discussion 旧的查找推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)findNotification:(JPushNotificationIdentifier *)identifier;
+
+/*!
+ * @abstract 本地推送,最多支持64个
+ *
+ * @param fireDate 本地推送触发的时间
+ * @param alertBody 本地推送需要显示的内容
+ * @param badge 角标的数字。如果不需要改变角标传-1
+ * @param alertAction 弹框的按钮显示的内容(IOS 8默认为"打开", 其他默认为"启动")
+ * @param notificationKey 本地推送标示符
+ * @param userInfo 自定义参数,可以用来标识推送和增加附加信息
+ * @param soundName 自定义通知声音,设置为nil为默认声音
+ *
+ * @discussion 最多支持 64 个定义,此方法被[addNotification:]方法取代
+ */
++ (UILocalNotification *)setLocalNotification:(NSDate *)fireDate
+ alertBody:(NSString *)alertBody
+ badge:(int)badge
+ alertAction:(NSString *)alertAction
+ identifierKey:(NSString *)notificationKey
+ userInfo:(NSDictionary *)userInfo
+ soundName:(NSString *)soundName __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 本地推送 (支持 iOS8 新参数)
+ *
+ * IOS8新参数
+ * @param region 自定义参数
+ * @param regionTriggersOnce 自定义参数
+ * @param category 自定义参数
+ * @discussion 此方法被[addNotification:]方法取代
+ */
++ (UILocalNotification *)setLocalNotification:(NSDate *)fireDate
+ alertBody:(NSString *)alertBody
+ badge:(int)badge
+ alertAction:(NSString *)alertAction
+ identifierKey:(NSString *)notificationKey
+ userInfo:(NSDictionary *)userInfo
+ soundName:(NSString *)soundName
+ region:(CLRegion *)region
+ regionTriggersOnce:(BOOL)regionTriggersOnce
+ category:(NSString *)category NS_AVAILABLE_IOS(8_0) __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 前台展示本地推送
+ *
+ * @param notification 本地推送对象
+ * @param notificationKey 需要前台显示的本地推送通知的标示符
+ *
+ * @discussion 默认App在前台运行时不会进行弹窗,在程序接收通知调用此接口可实现指定的推送弹窗。--iOS10以下还可继续使用,iOS10以上在[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:]方法中调用completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);即可
+ */
++ (void)showLocalNotificationAtFront:(UILocalNotification *)notification
+ identifierKey:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+/*!
+ * @abstract 删除本地推送定义
+ *
+ * @param notificationKey 本地推送标示符
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)deleteLocalNotificationWithIdentifierKey:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 删除本地推送定义
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)deleteLocalNotification:(UILocalNotification *)localNotification __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 获取指定通知
+ *
+ * @param notificationKey 本地推送标示符
+ * @return 本地推送对象数组, [array count]为0时表示没找到
+ * @discussion 此方法被[findNotification:]方法取代
+ */
++ (NSArray *)findLocalNotificationWithIdentifier:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 清除所有本地推送对象
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)clearAllLocalNotifications __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+
+///----------------------------------------------------
+/// @name Server badge 服务器端 badge 功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 设置角标(到服务器)
+ *
+ * @param value 新的值. 会覆盖服务器上保存的值(这个用户)
+ *
+ * @discussion 本接口不会改变应用本地的角标值.
+ * 本地仍须调用 UIApplication:setApplicationIconBadgeNumber 函数来设置脚标.
+ *
+ * 本接口用于配合 JPush 提供的服务器端角标功能.
+ * 该功能解决的问题是, 服务器端推送 APNs 时, 并不知道客户端原来已经存在的角标是多少, 指定一个固定的数字不太合理.
+ *
+ * JPush 服务器端脚标功能提供:
+ *
+ * - 通过本 API 把当前客户端(当前这个用户的) 的实际 badge 设置到服务器端保存起来;
+ * - 调用服务器端 API 发 APNs 时(通常这个调用是批量针对大量用户),
+ * 使用 "+1" 的语义, 来表达需要基于目标用户实际的 badge 值(保存的) +1 来下发通知时带上新的 badge 值;
+ */
++ (BOOL)setBadge:(NSInteger)value;
+
+/*!
+ * @abstract 重置脚标(为0)
+ *
+ * @discussion 相当于 [setBadge:0] 的效果.
+ * 参考 [JPUSHService setBadge:] 说明来理解其作用.
+ */
++ (void)resetBadge;
+
+///----------------------------------------------------
+/// @name Other Feature 其他功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 设置手机号码(到服务器)
+ *
+ * @param mobileNumber 手机号码. 会与用户信息一一对应。可为空,为空则清除号码
+ * @param completion 响应回调。成功则error为空,失败则error带有错误码及错误信息
+ *
+ * @discussion 设置手机号码后,可实现“推送不到短信到”的通知方式,提高推送达到率。结果信息通过completion异步返回,也可将completion设置为nil不处理结果信息。
+ *
+ */
++ (void)setMobileNumber:(NSString *)mobileNumber completion:(void (^)(NSError *error))completion;
+
+///----------------------------------------------------
+/// @name Logs and others 日志与其他
+///----------------------------------------------------
+
+/*!
+ * @abstract JPush标识此设备的 registrationID
+ *
+ * @discussion SDK注册成功后, 调用此接口获取到 registrationID 才能够获取到.
+ *
+ * JPush 支持根据 registrationID 来进行推送.
+ * 如果你需要此功能, 应该通过此接口获取到 registrationID 后, 上报到你自己的服务器端, 并保存下来.
+ * registrationIDCompletionHandler:是新增的获取registrationID的方法,需要在block中获取registrationID,resCode为返回码,模拟器调用此接口resCode返回1011,registrationID返回nil.
+ * 更多的理解请参考 JPush 的文档网站.
+ */
++ (NSString *)registrationID;
+
++ (void)registrationIDCompletionHandler:(void(^)(int resCode,NSString *registrationID))completionHandler;
+
+/*!
+ * @abstract 打开日志级别到 Debug
+ *
+ * @discussion JMessage iOS 的日志系统参考 Android 设计了级别.
+ * 从低到高是: Verbose, Debug, Info, Warning, Error.
+ * 对日志级别的进一步理解, 请参考 Android 相关的说明.
+ *
+ * SDK 默认开启的日志级别为: Info. 只显示必要的信息, 不打印调试日志.
+ *
+ * 请在SDK启动后调用本接口,调用本接口可打开日志级别为: Debug, 打印调试日志.
+ */
++ (void)setDebugMode;
+
+/*!
+ * @abstract 关闭日志
+ *
+ * @discussion 关于日志级别的说明, 参考 [JPUSHService setDebugMode]
+ *
+ * 虽说是关闭日志, 但还是会打印 Warning, Error 日志. 这二种日志级别, 在程序运行正常时, 不应有打印输出.
+ *
+ * 建议在发布的版本里, 调用此接口, 关闭掉日志打印.
+ */
++ (void)setLogOFF;
+
+///----------------------------------------------------
+///********************下列方法已过期********************
+///**************请使用新版tag/alias操作接口**************
+///----------------------------------------------------
+/// @name Tag alias setting 设置别名与标签
+///----------------------------------------------------
+
+/*!
+ * 下面的接口是可选的
+ * 设置标签和(或)别名(若参数为nil,则忽略;若是空对象,则清空;详情请参考文档:https://docs.jiguang.cn/jpush/client/iOS/ios_api/)
+ * setTags:alias:fetchCompletionHandle:是新的设置标签别名的方法,不再需要显示声明回调函数,只需要在block里面处理设置结果即可.
+ * WARN: 使用block时需要注意循环引用问题
+ */
++ (void) setTags:(NSSet *)tags
+ alias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ target:(id)theTarget __attribute__((deprecated("JPush 2.1.1 版本已过期")));
++ (void) setTags:(NSSet *)tags
+ alias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void) setTags:(NSSet *)tags
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void)setTags:(NSSet *)tags
+ alias:(NSString *)alias
+fetchCompletionHandle:(void (^)(int iResCode, NSSet *iTags, NSString *iAlias))completionHandler __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void) setTags:(NSSet *)tags
+aliasInbackground:(NSString *)alias __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void)setAlias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
+
+@end
+
+@class UNUserNotificationCenter;
+@class UNNotificationResponse;
+
+@protocol JPUSHRegisterDelegate <NSObject>
+
+/*
+ * @brief handle UserNotifications.framework [willPresentNotification:withCompletionHandler:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param notification 前台得到的的通知对象
+ * @param completionHandler 该callback中的options 请使用UNNotificationPresentationOptions
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger options))completionHandler;
+/*
+ * @brief handle UserNotifications.framework [didReceiveNotificationResponse:withCompletionHandler:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param response 通知响应对象
+ * @param completionHandler
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler;
+
+/*
+ * @brief handle UserNotifications.framework [openSettingsForNotification:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param notification 当前管理的通知对象
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification NS_AVAILABLE_IOS(12.0);
+
+@end
+
+@protocol JPUSHGeofenceDelegate <NSObject>
+
+/**
+ 进入地理围栏区域
+
+ @param geofenceId 地理围栏id
+ @param userInfo 地理围栏触发时返回的信息
+ @param error 错误信息
+ */
+- (void)jpushGeofenceIdentifer:(NSString * _Nonnull)geofenceId didEnterRegion:(NSDictionary * _Nullable)userInfo error:(NSError * _Nullable)error;
+
+/**
+ 离开地理围栏区域
+
+ @param geofenceId 地理围栏id
+ @param userInfo 地理围栏触发时返回的信息
+ @param error 错误信息
+ */
+- (void)jpushGeofenceIdentifer:(NSString * _Nonnull)geofenceId didExitRegion:(NSDictionary * _Nullable)userInfo error:(NSError * _Nullable)error;
+
+@end
--- /dev/null
+//
+// ConstantDef.h
+// jmessage
+//
+// Created by ljg on 16/1/19.
+//
+//
+
+#ifndef ConstantDef_h
+#define ConstantDef_h
+
+
+
+#endif /* ConstantDef_h */
+
+#define WEAK_SELF(weakSelf) __weak __typeof(&*self)weakSelf = self;
+
+static NSString *const JPushConfig_FileName = @"JPushConfig";
+static NSString *const JPushConfig_Appkey = @"Appkey";
+static NSString *const JPushConfig_Channel = @"Channel";
+static NSString *const JPushConfig_IsProduction = @"IsProduction";
+static NSString *const JPushConfig_IsIDFA = @"IsIDFA";
+static NSString *const JPushConfig_Delay = @"Delay";
+
+static NSString *const JPushDocumentEvent_ReceiveNotification = @"receiveNotification";
+static NSString *const JPushDocumentEvent_OpenNotification = @"openNotification";
+static NSString *const JPushDocumentEvent_BackgroundNotification = @"backgroundNotification";
+static NSString *const JPushDocumentEvent_SetTagsWithAlias = @"setTagsWithAlias";
+static NSString *const JPushDocumentEvent_ReceiveMessage = @"receiveMessage";
+static NSString *const JPushDocumentEvent_ReceiveLocalNotification = @"receiveLocalNotification";
+
+static NSString *const JPushDocumentEvent_receiveRegistrationId = @"receiveRegistrationId";
--- /dev/null
+//
+// PushTalkPlugin.h
+// PushTalk
+//
+// Created by zhangqinghe on 13-12-13.
+//
+//
+
+#import <Cordova/CDV.h>
+
+static NSMutableDictionary *_jpushEventCache;
+
+@interface JPushPlugin : CDVPlugin{
+
+}
+
+//注册通知服务并启动 SDK
+-(void)startJPushSDK:(CDVInvokedUrlCommand*)command;
+
+//以下为js中可调用接口
+//设置标签、别名
+-(void)setTags:(CDVInvokedUrlCommand*)command;
+-(void)addTags:(CDVInvokedUrlCommand*)command;
+-(void)deleteTags:(CDVInvokedUrlCommand*)command;
+-(void)cleanTags:(CDVInvokedUrlCommand*)command;
+-(void)getAllTags:(CDVInvokedUrlCommand*)command;
+-(void)checkTagBindState:(CDVInvokedUrlCommand*)command;
+
+-(void)setAlias:(CDVInvokedUrlCommand*)command;
+-(void)deleteAlias:(CDVInvokedUrlCommand*)command;
+-(void)getAlias:(CDVInvokedUrlCommand*)command;
+
+//获取 RegistrationID
+-(void)getRegistrationID:(CDVInvokedUrlCommand*)command;
+
+//页面统计
+-(void)startLogPageView:(CDVInvokedUrlCommand*)command;
+-(void)stopLogPageView:(CDVInvokedUrlCommand*)command;
+-(void)beginLogPageView:(CDVInvokedUrlCommand*)command;
+
+//设置角标到服务器,服务器下一次发消息时,会设置成这个值
+//本接口不会改变应用本地的角标值.
+-(void)setBadge:(CDVInvokedUrlCommand*)command;
+//相当于 [setBadge:0]
+-(void)resetBadge:(CDVInvokedUrlCommand*)command;
+
+//应用本地的角标值设置/获取
+-(void)setApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command;
+-(void)getApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command;
+
+//停止与恢复推送
+-(void)stopPush:(CDVInvokedUrlCommand*)command;
+-(void)resumePush:(CDVInvokedUrlCommand*)command;
+-(void)isPushStopped:(CDVInvokedUrlCommand*)command;
+
+//开关日志
+-(void)setDebugModeFromIos:(CDVInvokedUrlCommand*)command;
+-(void)setLogOFF:(CDVInvokedUrlCommand*)command;
+-(void)crashLogON:(CDVInvokedUrlCommand*)command;
+
+//本地推送
+-(void)setLocalNotification:(CDVInvokedUrlCommand*)command;
+-(void)deleteLocalNotificationWithIdentifierKey:(CDVInvokedUrlCommand*)command;
+-(void)clearAllLocalNotifications:(CDVInvokedUrlCommand*)command;
+
+//地理位置上报 [latitude,longitude]
+-(void)setLocation:(CDVInvokedUrlCommand*)command;
+
+//检查用户的推送设置情况
+-(void)getUserNotificationSettings:(CDVInvokedUrlCommand*)command;
+
+//ios 10 APIs
+-(void)addDismissActions:(CDVInvokedUrlCommand*)command;
+-(void)addNotificationActions:(CDVInvokedUrlCommand*)command;
+
+/*
+ * 以下为js中可监听到的事件
+ * jpush.openNotification 点击推送消息启动或唤醒app
+ * jpush.receiveMessage 收到自定义消息
+ * jpush.receiveNotification 前台收到推送
+ * jpush.backgroundNotification 后台收到推送
+ */
+
+# pragma mark - private
+
++(void)fireDocumentEvent:(NSString*)eventName jsString:(NSString*)jsString;
+
++(void)setupJPushSDK:(NSDictionary*)userInfo;
+
+@end
+
+static JPushPlugin *SharedJPushPlugin;
+
+@interface NSDictionary (JPush)
+-(NSString*)toJsonString;
+@end
+
+@interface NSString (JPush)
+-(NSDictionary*)toDictionary;
+@end
+
+
--- /dev/null
+#import "JPushPlugin.h"
+#import "JPUSHService.h"
+#import <UIKit/UIKit.h>
+#import <AdSupport/AdSupport.h>
+#import <UserNotifications/UserNotifications.h>
+#import "AppDelegate+JPush.h"
+#import "JPushDefine.h"
+
+@implementation NSDictionary (JPush)
+-(NSString*)toJsonString{
+ NSError *error;
+ NSData *data = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
+ NSString *jsonString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
+ return jsonString;
+}
+@end
+
+@implementation NSString (JPush)
+-(NSDictionary*)toDictionary{
+ NSError *error;
+ NSData *jsonData = [self dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
+ return dict;
+}
+@end
+
+@interface JPushPlugin()
+
+@end
+
+@implementation JPushPlugin
+
+-(void)startJPushSDK:(CDVInvokedUrlCommand*)command{
+ [(AppDelegate*)[UIApplication sharedApplication].delegate startJPushSDK];
+}
+
+#pragma mark- 外部接口
+-(void)stopPush:(CDVInvokedUrlCommand*)command{
+ [[UIApplication sharedApplication]unregisterForRemoteNotifications];
+}
+
+-(void)resumePush:(CDVInvokedUrlCommand*)command{
+ [(AppDelegate*)[UIApplication sharedApplication].delegate registerForRemoteNotification];
+}
+
+-(void)isPushStopped:(CDVInvokedUrlCommand*)command{
+ NSNumber *result = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications] ? @(0) : @(1);
+ [self handleResultWithValue:result command:command];
+}
+
+-(void)initial:(CDVInvokedUrlCommand*)command{
+ //do nithng,because Cordova plugin use lazy load mode.
+}
+
+#ifdef __CORDOVA_4_0_0
+
+- (void)pluginInitialize {
+ NSLog(@"### pluginInitialize ");
+ [self initPlugin];
+}
+
+#else
+
+- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView{
+ NSLog(@"### initWithWebView ");
+ if (self=[super initWithWebView:theWebView]) {
+ }
+ [self initPlugin];
+ return self;
+}
+
+#endif
+
+-(void)initPlugin{
+ if (!SharedJPushPlugin) {
+ SharedJPushPlugin = self;
+ }
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(networkDidReceiveMessage:)
+ name:kJPFNetworkDidReceiveMessageNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(receiveLocalNotification:)
+ name:JPushDocumentEvent_ReceiveLocalNotification
+ object:nil];
+ [self dispatchJPushCacheEvent];
+}
+
+- (void)dispatchJPushCacheEvent {
+ for (NSString* key in _jpushEventCache) {
+ NSArray *evenList = _jpushEventCache[key];
+ for (NSString *event in evenList) {
+ [JPushPlugin fireDocumentEvent:key jsString:event];
+ }
+ }
+}
+
++(void)fireDocumentEvent:(NSString*)eventName jsString:(NSString*)jsString{
+ if (SharedJPushPlugin) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [SharedJPushPlugin.commandDelegate evalJs:[NSString stringWithFormat:@"cordova.fireDocumentEvent('jpush.%@',%@)", eventName, jsString]];
+ });
+ return;
+ }
+
+ if (!_jpushEventCache) {
+ _jpushEventCache = @{}.mutableCopy;
+ }
+
+ if (!_jpushEventCache[eventName]) {
+ _jpushEventCache[eventName] = @[].mutableCopy;
+ }
+
+ [_jpushEventCache[eventName] addObject: jsString];
+}
+
+-(void)setTags:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService setTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)addTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService addTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)deleteTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService deleteTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)cleanTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService cleanTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getAllTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService getAllTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)checkTagBindState:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSString* tag = params[@"tag"];
+
+ [JPUSHService validTag:tag completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq, BOOL isBind) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ dic[@"tag"] = tag;
+ [dic setObject:[NSNumber numberWithBool:isBind] forKey:@"isBind"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)setAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSString* alias = params[@"alias"];
+
+ [JPUSHService setAlias:alias completion:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:iAlias forKey:@"alias"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)deleteAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService deleteAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService getAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:iAlias forKey:@"alias"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getRegistrationID:(CDVInvokedUrlCommand*)command{
+ NSString* registrationID = [JPUSHService registrationID];
+ [self handleResultWithValue:registrationID command:command];
+}
+
+-(void)startLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString * pageName = [command argumentAtIndex:0];
+ [JPUSHService startLogPageView:pageName];
+}
+
+-(void)stopLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString * pageName = [command argumentAtIndex:0];
+ [JPUSHService stopLogPageView:pageName];
+}
+
+-(void)beginLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString *pageName = [command argumentAtIndex:0];
+ NSNumber *duration = [command argumentAtIndex:1];
+ [JPUSHService beginLogPageView:pageName duration:duration.intValue];
+}
+
+-(void)setBadge:(CDVInvokedUrlCommand*)command{
+ NSNumber *badge = [command argumentAtIndex:0];
+ [JPUSHService setBadge:badge.intValue];
+}
+
+-(void)resetBadge:(CDVInvokedUrlCommand*)command{
+ [JPUSHService resetBadge];
+}
+
+-(void)setApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command{
+ NSNumber *badge = [command argumentAtIndex:0];
+ [UIApplication sharedApplication].applicationIconBadgeNumber = badge.intValue;
+}
+
+-(void)getApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command {
+ NSInteger num = [UIApplication sharedApplication].applicationIconBadgeNumber;
+ NSNumber *number = [NSNumber numberWithInteger:num];
+ [self handleResultWithValue:number command:command];
+}
+
+-(void)setDebugModeFromIos:(CDVInvokedUrlCommand*)command{
+ [JPUSHService setDebugMode];
+}
+
+-(void)setLogOFF:(CDVInvokedUrlCommand*)command{
+ [JPUSHService setLogOFF];
+}
+
+-(void)crashLogON:(CDVInvokedUrlCommand*)command{
+ [JPUSHService crashLogON];
+}
+
+-(void)setLocalNotification:(CDVInvokedUrlCommand*)command{
+ NSNumber *delay = [command argumentAtIndex:0];
+ NSString *alert = [command argumentAtIndex:1];
+ NSNumber *badge = [command argumentAtIndex:2];
+ NSString *idKey = [command argumentAtIndex:3];
+ NSDictionary *userInfo = [command argumentAtIndex:4];
+
+ JPushNotificationContent *content = [[JPushNotificationContent alloc] init];
+
+ if (alert) {
+ content.body = alert;
+ }
+
+ if (badge) {
+ content.badge = badge;
+ }
+
+ if (userInfo) {
+ content.userInfo = userInfo;
+ }
+
+ JPushNotificationTrigger *trigger = [[JPushNotificationTrigger alloc] init];
+ // 由于 不支持 0 作为传入参数,在传入参数基础上添加一个极小的时间于 android 端保持一致。
+ if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
+ if (delay) {
+ trigger.timeInterval = [delay doubleValue] + 0.000001;
+ }
+ } else {
+ if (delay) {
+ trigger.fireDate = [NSDate dateWithTimeIntervalSinceNow:[[command argumentAtIndex:0] doubleValue] + 0.001];
+ }
+ }
+
+ JPushNotificationRequest *request = [[JPushNotificationRequest alloc] init];
+ request.content = content;
+ request.trigger = trigger;
+
+ if (idKey) {
+ request.requestIdentifier = idKey;
+ }
+
+ request.completionHandler = ^(id result) {
+ NSLog(@"result");
+ };
+
+ [JPUSHService addNotification:request];
+}
+
+-(void)deleteLocalNotificationWithIdentifierKey:(CDVInvokedUrlCommand*)command{
+ NSString *identifier = [command argumentAtIndex:0];
+ JPushNotificationIdentifier *jpid = [JPushNotificationIdentifier new];
+ jpid.identifiers = @[identifier];
+ [JPUSHService removeNotification:jpid];
+}
+
+-(void)clearAllLocalNotifications:(CDVInvokedUrlCommand*)command{
+ [JPUSHService removeNotification:nil];
+}
+
+-(void)setLocation:(CDVInvokedUrlCommand*)command{
+ NSNumber *latitude = [command argumentAtIndex:0];
+ NSNumber *longitude = [command argumentAtIndex:1];
+ [JPUSHService setLatitude:latitude.doubleValue longitude:longitude.doubleValue];
+}
+
+-(void)getUserNotificationSettings:(CDVInvokedUrlCommand*)command{
+ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+ WEAK_SELF(weakSelf);
+ [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+ dict[@"authorizationStatus"] = @(settings.authorizationStatus);
+ dict[@"soundSetting"] = @(settings.soundSetting);
+ dict[@"badgeSetting"] = @(settings.badgeSetting);
+ dict[@"alertSetting"] = @(settings.alertSetting);
+ dict[@"notificationCenterSetting"] = @(settings.notificationCenterSetting);
+ dict[@"lockScreenSetting"] = @(settings.lockScreenSetting);
+ dict[@"carPlaySetting"] = @(settings.carPlaySetting);
+ dict[@"alertStyle"] = @(settings.alertStyle);
+ [weakSelf handleResultWithValue:dict command:command];
+ }];
+ }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
+ UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings];
+ UIUserNotificationType type = settings.types;
+ NSNumber *number = [NSNumber numberWithInteger:type];
+ [self handleResultWithValue:number command:command];
+ }else{
+ UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
+ NSNumber *number = [NSNumber numberWithInteger:type];
+ [self handleResultWithValue:number command:command];
+ }
+}
+
+#pragma mark - ios 10 APIs
+
+-(void)addDismissActions:(CDVInvokedUrlCommand*)command{
+ [self addActions:command dismiss:YES];
+}
+
+-(void)addNotificationActions:(CDVInvokedUrlCommand*)command{
+ [self addActions:command dismiss:NO];
+}
+
+-(void)addActions:(CDVInvokedUrlCommand*)command dismiss:(BOOL)dimiss{
+ NSArray *actionsData = [command argumentAtIndex:0];
+ NSString *categoryId = [command argumentAtIndex:1];
+ NSMutableArray *actions = [NSMutableArray array];
+ for (NSDictionary *dict in actionsData) {
+ NSString *title = dict[@"title"];
+ NSString *identifier = dict[@"identifier"];
+ NSString *option = dict[@"option"];
+ NSString *type = dict[@"type"];
+ if ([type isEqualToString:@"textInput"]) {
+ NSString *textInputButtonTitle = dict[@"textInputButtonTitle"];
+ NSString *textInputPlaceholder = dict[@"textInputPlaceholder"];
+ UNTextInputNotificationAction *inputAction = [UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:option.integerValue textInputButtonTitle:textInputButtonTitle textInputPlaceholder:textInputPlaceholder];
+ [actions addObject:inputAction];
+ } else {
+ UNNotificationAction *action = [UNNotificationAction actionWithIdentifier:title title:title options:option.integerValue];
+ [actions addObject:action];
+ }
+ }
+ UNNotificationCategory *category;
+ if (dimiss) {
+ category = [UNNotificationCategory categoryWithIdentifier:categoryId
+ actions:actions
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionCustomDismissAction];
+ } else {
+ category = [UNNotificationCategory categoryWithIdentifier:categoryId
+ actions:actions
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionNone];
+ }
+ [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:category]];
+}
+
+#pragma mark - 内部方法
+
++(void)setupJPushSDK:(NSDictionary*)userInfo{
+ NSString *plistPath = [[NSBundle mainBundle] pathForResource:JPushConfig_FileName ofType:@"plist"];
+ if (plistPath == nil) {
+ NSLog(@"error: PushConfig.plist not found");
+ assert(0);
+ }
+
+ NSMutableDictionary *plistData = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+ NSString *appkey = [plistData valueForKey:JPushConfig_Appkey];
+ NSString *channel = [plistData valueForKey:JPushConfig_Channel];
+ NSNumber *isProduction = [plistData valueForKey:JPushConfig_IsProduction];
+ NSNumber *isIDFA = [plistData valueForKey:JPushConfig_IsIDFA];
+
+ NSString *advertisingId = nil;
+ if(isIDFA.boolValue) {
+ advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
+ }
+ [JPUSHService setupWithOption:userInfo
+ appKey:appkey
+ channel:channel
+ apsForProduction:[isProduction boolValue]
+ advertisingIdentifier:advertisingId];
+}
+
+#pragma mark 将参数返回给js
+-(void)handleResultWithValue:(id)value command:(CDVInvokedUrlCommand*)command {
+ CDVPluginResult *result = nil;
+ CDVCommandStatus status = CDVCommandStatus_OK;
+
+ if ([value isKindOfClass:[NSString class]]) {
+ value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ } else if ([value isKindOfClass:[NSNull class]]) {
+ value = nil;
+ }
+
+ if ([value isKindOfClass:[NSObject class]]) {
+ result = [CDVPluginResult resultWithStatus:status messageAsString:value];//NSObject 类型都可以
+ } else {
+ NSLog(@"Cordova callback block returned unrecognized type: %@", NSStringFromClass([value class]));
+ result = nil;
+ }
+
+ if (!result) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
+ }
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+}
+
+-(void)networkDidReceiveMessage:(NSNotification *)notification {
+ if (notification && notification.userInfo) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveMessage
+ jsString:[notification.userInfo toJsonString]];
+ }
+}
+
+-(void)receiveLocalNotification:(NSNotification *)notification {
+ if (notification && notification.object) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveLocalNotification
+ jsString:[notification.object toJsonString]];
+ }
+}
+@end
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Appkey</key>
+ <string>your_jpush_appkey</string>
+ <key>Channel</key>
+ <string>channel name</string>
+ <key>IsProduction</key>
+ <false/>
+ <key>IsIDFA</key>
+ <false/>
+ <key>Delay</key>
+ <false/>
+</dict>
+</plist>
\ No newline at end of file
<feature name="ThemeableBrowser">
<param name="ios-package" value="CDVThemeableBrowser" />
</feature>
+ <feature name="JPushPlugin">
+ <param name="ios-package" value="JPushPlugin" />
+ </feature>
<name short="大理市民卡">dlapp</name>
<description>
A sample Apache Cordova application that responds to the deviceready event.
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
+ <key>UIBackgroundModes</key>
+ <array>
+ <string>remote-notification</string>
+ </array>
</dict>
</plist>
\ No newline at end of file
{
- "Security.framework": 2,
- "SystemConfiguration.framework": 1,
+ "Security.framework": 3,
+ "SystemConfiguration.framework": 2,
"LocalAuthentication.framework": 1,
"ImageIO.framework": 1,
"CoreLocation.framework": 1,
- "AVFoundation.framework": 1
+ "AVFoundation.framework": 1,
+ "CFNetwork.framework": 1,
+ "CoreFoundation.framework": 1,
+ "CoreTelephony.framework": 1,
+ "Foundation.framework": 1,
+ "UIKit.framework": 1,
+ "libz.tbd": 1,
+ "AdSupport.framework": 1,
+ "UserNotifications.framework": 1,
+ "libresolv.tbd": 1
}
\ No newline at end of file
{
"xml": "<feature name=\"ThemeableBrowser\"><param name=\"ios-package\" value=\"CDVThemeableBrowser\" /></feature>",
"count": 1
+ },
+ {
+ "xml": "<feature name=\"JPushPlugin\"><param name=\"ios-package\" value=\"JPushPlugin\" /></feature>",
+ "count": 1
}
]
}
"mode": "merge",
"id": "config.xml"
}
+ ],
+ "UIBackgroundModes": [
+ {
+ "xml": "<array><string>remote-notification</string></array>",
+ "count": 1
+ }
+ ]
+ }
+ },
+ "*-Debug.plist": {
+ "parents": {
+ "aps-environment": [
+ {
+ "xml": "<string>development</string>",
+ "count": 1
+ }
+ ]
+ }
+ },
+ "*-Release.plist": {
+ "parents": {
+ "aps-environment": [
+ {
+ "xml": "<string>production</string>",
+ "count": 1
+ }
+ ]
+ }
+ },
+ "*JPushConfig.plist": {
+ "parents": {
+ "Appkey": [
+ {
+ "xml": "<string>your_jpush_appkey</string>",
+ "count": 1
+ }
]
}
}
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
}
},
"dependent_plugins": {},
"clobbers": [
"cordova.ThemeableBrowser"
]
+ },
+ {
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
],
"plugin_metadata": {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
}
}
"clobbers": [
"cordova.ThemeableBrowser"
]
+ },
+ {
+ "id": "jpush-phonegap-plugin.JPushPlugin",
+ "file": "plugins/jpush-phonegap-plugin/www/JPushPlugin.js",
+ "pluginId": "jpush-phonegap-plugin",
+ "clobbers": [
+ "JPush"
+ ]
}
];
module.exports.metadata = {
"cordova-plugin-camera": "4.0.3",
"cordova-plugin-inappbrowser": "3.0.0",
"cordova-plugin-device": "2.0.2",
- "cordova-plugin-themeablebrowser": "0.2.17"
+ "cordova-plugin-themeablebrowser": "0.2.17",
+ "cordova-plugin-jcore": "1.3.0",
+ "jpush-phonegap-plugin": "3.7.2"
};
});
\ No newline at end of file
--- /dev/null
+cordova.define("jpush-phonegap-plugin.JPushPlugin", function(require, exports, module) {
+var JPushPlugin = function() {};
+
+// private plugin function
+
+JPushPlugin.prototype.receiveMessage = {};
+JPushPlugin.prototype.openNotification = {};
+JPushPlugin.prototype.receiveNotification = {};
+
+JPushPlugin.prototype.isPlatformIOS = function() {
+ return (
+ device.platform === "iPhone" ||
+ device.platform === "iPad" ||
+ device.platform === "iPod touch" ||
+ device.platform === "iOS"
+ );
+};
+
+JPushPlugin.prototype.errorCallback = function(msg) {
+ console.log("JPush Callback Error: " + msg);
+};
+
+JPushPlugin.prototype.callNative = function(
+ name,
+ args,
+ successCallback,
+ errorCallback
+) {
+ if (errorCallback) {
+ cordova.exec(successCallback, errorCallback, "JPushPlugin", name, args);
+ } else {
+ cordova.exec(
+ successCallback,
+ this.errorCallback,
+ "JPushPlugin",
+ name,
+ args
+ );
+ }
+};
+
+// Common methods
+JPushPlugin.prototype.init = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("initial", [], null);
+ } else {
+ this.callNative("init", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugMode = function(mode) {
+ if (device.platform === "Android") {
+ this.callNative("setDebugMode", [mode], null);
+ } else {
+ if (mode === true) {
+ this.setDebugModeFromIos();
+ } else {
+ this.setLogOFF();
+ }
+ }
+};
+
+JPushPlugin.prototype.getRegistrationID = function(successCallback) {
+ this.callNative("getRegistrationID", [], successCallback);
+};
+
+JPushPlugin.prototype.stopPush = function() {
+ this.callNative("stopPush", [], null);
+};
+
+JPushPlugin.prototype.resumePush = function() {
+ this.callNative("resumePush", [], null);
+};
+
+JPushPlugin.prototype.isPushStopped = function(successCallback) {
+ this.callNative("isPushStopped", [], successCallback);
+};
+
+JPushPlugin.prototype.clearLocalNotifications = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearLocalNotifications", [], null);
+ } else {
+ this.clearAllLocalNotifications();
+ }
+};
+
+/**
+ * 设置标签。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.setTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 新增标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.addTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("addTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除指定标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.deleteTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 清除所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.cleanTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("cleanTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAllTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAllTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询指定标签与当前用户的绑定状态。
+ *
+ * @param params = { 'sequence': number, 'tag': string }
+ */
+JPushPlugin.prototype.checkTagBindState = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative(
+ "checkTagBindState",
+ [params],
+ successCallback,
+ errorCallback
+ );
+};
+
+/**
+ * 设置别名。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'alias': string }
+ */
+JPushPlugin.prototype.setAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.deleteAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询当前绑定的别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAlias", [params], successCallback, errorCallback);
+};
+
+// 判断系统设置中是否对本应用启用通知。
+// iOS: 返回值如果大于 0,代表通知开启;0: 通知关闭。
+// UIRemoteNotificationTypeNone = 0,
+// UIRemoteNotificationTypeBadge = 1 << 0,
+// UIRemoteNotificationTypeSound = 1 << 1,
+// UIRemoteNotificationTypeAlert = 1 << 2,
+// UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
+// Android: 返回值 1 代表通知启用;0: 通知关闭。
+JPushPlugin.prototype.getUserNotificationSettings = function(successCallback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getUserNotificationSettings", [], successCallback);
+ } else if (device.platform === "Android") {
+ this.callNative("areNotificationEnabled", [], successCallback);
+ }
+};
+
+// iOS methods
+
+JPushPlugin.prototype.startJPushSDK = function() {
+ this.callNative("startJPushSDK", [], null);
+};
+
+JPushPlugin.prototype.setBadge = function(value) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setBadge", [value], null);
+ }
+};
+
+JPushPlugin.prototype.resetBadge = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("resetBadge", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugModeFromIos = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setDebugModeFromIos", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLogOFF = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLogOFF", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCrashLogON = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("crashLogON", [], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotificationForIOS = function(
+ delayTime,
+ content,
+ badge,
+ notificationID,
+ extras
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "setLocalNotification",
+ [delayTime, content, badge, notificationID, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function(
+ identifierKey
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "deleteLocalNotificationWithIdentifierKey",
+ [identifierKey],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.clearAllLocalNotifications = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("clearAllLocalNotifications", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLocation = function(latitude, longitude) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLocation", [latitude, longitude], null);
+ }
+};
+
+JPushPlugin.prototype.startLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("startLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.stopLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("stopLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.beginLogPageView = function(pageName, duration) {
+ if (this.isPlatformIOS()) {
+ this.callNative("beginLogPageView", [pageName, duration], null);
+ }
+};
+
+JPushPlugin.prototype.setApplicationIconBadgeNumber = function(badge) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setApplicationIconBadgeNumber", [badge], null);
+ }
+};
+
+JPushPlugin.prototype.getApplicationIconBadgeNumber = function(callback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getApplicationIconBadgeNumber", [], callback);
+ }
+};
+
+JPushPlugin.prototype.addDismissActions = function(actions, categoryId) {
+ this.callNative("addDismissActions", [actions, categoryId]);
+};
+
+JPushPlugin.prototype.addNotificationActions = function(actions, categoryId) {
+ this.callNative("addNotificationActions", [actions, categoryId]);
+};
+
+// Android methods
+JPushPlugin.prototype.getConnectionState = function(successCallback) {
+ if (device.platform === "Android") {
+ this.callNative("getConnectionState", [], successCallback);
+ }
+};
+
+JPushPlugin.prototype.setBasicPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setBasicPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCustomPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setCustomPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.receiveRegistrationIdInAndroidCallback = function(data) {
+ if (device.platform === "Android") {
+ data = JSON.stringify(data);
+ var event = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveRegistrationId", event);
+ }
+};
+
+JPushPlugin.prototype.receiveMessageInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveMessage = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveMessage", this.receiveMessage);
+};
+
+JPushPlugin.prototype.openNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.openNotification = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.openNotification", this.openNotification);
+};
+
+JPushPlugin.prototype.receiveNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveNotification = JSON.parse(data);
+ cordova.fireDocumentEvent(
+ "jpush.receiveNotification",
+ this.receiveNotification
+ );
+};
+
+JPushPlugin.prototype.clearAllNotification = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearAllNotification", [], null);
+ }
+};
+
+JPushPlugin.prototype.clearNotificationById = function(id) {
+ if (device.platform === "Android") {
+ this.callNative("clearNotificationById", [id], null);
+ }
+};
+
+JPushPlugin.prototype.setLatestNotificationNum = function(num) {
+ if (device.platform === "Android") {
+ this.callNative("setLatestNotificationNum", [num], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotification = function(
+ builderId,
+ content,
+ title,
+ notificationID,
+ broadcastTime,
+ extras
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "addLocalNotification",
+ [builderId, content, title, notificationID, broadcastTime, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.removeLocalNotification = function(notificationID) {
+ if (device.platform === "Android") {
+ this.callNative("removeLocalNotification", [notificationID], null);
+ }
+};
+
+JPushPlugin.prototype.reportNotificationOpened = function(msgID) {
+ if (device.platform === "Android") {
+ this.callNative("reportNotificationOpened", [msgID], null);
+ }
+};
+
+/**
+ * 用于在 Android 6.0 及以上系统,申请一些权限
+ * 具体可看:http://docs.jpush.io/client/android_api/#android-60
+ */
+JPushPlugin.prototype.requestPermission = function() {
+ if (device.platform === "Android") {
+ this.callNative("requestPermission", [], null);
+ }
+};
+
+JPushPlugin.prototype.setSilenceTime = function(
+ startHour,
+ startMinute,
+ endHour,
+ endMinute
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "setSilenceTime",
+ [startHour, startMinute, endHour, endMinute],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.setPushTime = function(weekdays, startHour, endHour) {
+ if (device.platform === "Android") {
+ this.callNative("setPushTime", [weekdays, startHour, endHour], null);
+ }
+};
+
+JPushPlugin.prototype.setGeofenceInterval = function(interval) {
+ if (device.platform === "Android") {
+ this.callNative("setGeofenceInterval", [interval], null);
+ }
+};
+
+JPushPlugin.prototype.setMaxGeofenceNumber = function(maxNumber) {
+ if (device.platform === "Android") {
+ this.callNative("setMaxGeofenceNumber", [maxNumber], null);
+ }
+};
+
+if (!window.plugins) {
+ window.plugins = {};
+}
+
+if (!window.plugins.jPushPlugin) {
+ window.plugins.jPushPlugin = new JPushPlugin();
+}
+
+module.exports = new JPushPlugin();
+
+});
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
// DO NOT MODIFY -- auto-generated by Apache Cordova
+#include "Pods/Target Support Files/Pods-dlapp/Pods-dlapp.debug.xcconfig"
\ No newline at end of file
-//
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-
-// DO NOT MODIFY -- auto-generated by Apache Cordova
\ No newline at end of file
+// DO NOT MODIFY -- auto-generated by Apache Cordova
+#include "Pods/Target Support Files/Pods-dlapp/Pods-dlapp.release.xcconfig"
\ No newline at end of file
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
},
"dependent_plugins": {
},
"cordova-plugin-file": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
}
}
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
},
"dependent_plugins": {
},
"cordova-plugin-file": {
"PACKAGE_NAME": "com.supwisdom.dlapp"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "com.supwisdom.dlapp"
}
}
}
--- /dev/null
+MIT License
+
+Copyright (c) 2017 极光开发者
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+{
+ "_from": "cordova-plugin-jcore",
+ "_id": "cordova-plugin-jcore@1.3.0",
+ "_inBundle": false,
+ "_integrity": "sha512-QmkdABlkIHFaMUBsrjPqhpaWS7wuboRPeeVEUNoc4FlZNRoQgw35v0MaW+SbOk4SzVsEGvN6IFSVqa4106ljUw==",
+ "_location": "/cordova-plugin-jcore",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "tag",
+ "registry": true,
+ "raw": "cordova-plugin-jcore",
+ "name": "cordova-plugin-jcore",
+ "escapedName": "cordova-plugin-jcore",
+ "rawSpec": "",
+ "saveSpec": null,
+ "fetchSpec": "latest"
+ },
+ "_requiredBy": [
+ "#USER",
+ "/"
+ ],
+ "_resolved": "https://registry.npmjs.org/cordova-plugin-jcore/-/cordova-plugin-jcore-1.3.0.tgz",
+ "_shasum": "040e792f48039ee4c50631a9b2e0e5c4bf8aa967",
+ "_spec": "cordova-plugin-jcore",
+ "_where": "/Users/shuwei/works2/cordova/dlapp",
+ "author": {
+ "name": "wilhantian, jiguang"
+ },
+ "bugs": {
+ "url": "https://github.com/jpush/cordova-plugin-jcore/issues"
+ },
+ "bundleDependencies": false,
+ "cordova": {
+ "id": "cordova-plugin-jcore",
+ "platforms": [
+ "android",
+ "ios"
+ ]
+ },
+ "deprecated": false,
+ "description": "jcore for cordova plugin",
+ "homepage": "https://github.com/jpush/cordova-plugin-jcore#readme",
+ "keywords": [
+ "jcore",
+ "jpush",
+ "ecosystem:cordova",
+ "cordova-android",
+ "cordova-ios"
+ ],
+ "license": "MIT License",
+ "name": "cordova-plugin-jcore",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/jpush/cordova-plugin-jcore.git"
+ },
+ "version": "1.3.0"
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ id="cordova-plugin-jcore"
+ version="1.3.0">
+
+ <name>JCore</name>
+ <description>Cordova plugin for jcore</description>
+ <author>WilhanTian, JiGuang</author>
+ <keywords>jcore,jpush</keywords>
+ <license>MIT License</license>
+
+ <engines>
+ <engine name="cordova" version=">=3.0.0"/>
+ </engines>
+
+ <platform name="android">
+ <resource-file src="src/android/arm64-v8a/libjcore212.so" target="jniLibs/arm64-v8a/libjcore212.so"/>
+ <resource-file src="src/android/armeabi/libjcore212.so" target="jniLibs/armeabi/libjcore212.so"/>
+ <resource-file src="src/android/armeabi-v7a/libjcore212.so" target="jniLibs/armeabi-v7a/libjcore212.so"/>
+ <resource-file src="src/android/mips/libjcore212.so" target="jniLibs/mips/libjcore212.so"/>
+ <resource-file src="src/android/mips64/libjcore212.so" target="jniLibs/mips64/libjcore212.so"/>
+ <resource-file src="src/android/x86/libjcore212.so" target="jniLibs/x86/libjcore212.so"/>
+ <resource-file src="src/android/x86_64/libjcore212.so" target="jniLibs/x86_64/libjcore212.so"/>
+
+ <lib-file src="src/android/jcore-android-2.1.2.jar" />
+ </platform>
+
+ <platform name="ios">
+ <source-file src="src/ios/jcore-ios-2.1.1.a" framework="true" />
+ </platform>
+</plugin>
--- /dev/null
+var exec = require('cordova/exec')
+
+exports.coolMethod = function (arg0, success, error) {
+ exec(success, error, 'jcore', 'coolMethod', [arg0])
+}
},
"is_top_level": true,
"variables": {}
+ },
+ "jpush-phonegap-plugin": {
+ "source": {
+ "type": "registry",
+ "id": "jpush-phonegap-plugin"
+ },
+ "is_top_level": true,
+ "variables": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default"
+ }
+ },
+ "cordova-plugin-jcore": {
+ "source": {
+ "type": "registry",
+ "id": "cordova-plugin-jcore"
+ },
+ "is_top_level": false,
+ "variables": {}
}
}
\ No newline at end of file
},
"cordova-plugin-themeablebrowser": {
"PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
+ },
+ "jpush-phonegap-plugin": {
+ "APP_KEY": "your_jpush_appkey",
+ "CHANNEL": "developer-default",
+ "PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
}
},
"dependent_plugins": {
},
"cordova-plugin-file": {
"PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
+ },
+ "cordova-plugin-jcore": {
+ "PACKAGE_NAME": "$(PRODUCT_BUNDLE_IDENTIFIER)"
}
}
}
--- /dev/null
+language: node_js
+sudo: false
+node_js:
+ - "4.2"
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+* {
+ -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+}
+
+body {
+ -webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
+ -webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
+ -webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
+ background-color:#E4E4E4;
+ background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+ background-image:-webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0, #A7A7A7),
+ color-stop(0.51, #E4E4E4)
+ );
+ background-attachment:fixed;
+ font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+ font-size:12px;
+ height:100%;
+ margin:0px;
+ padding:0px;
+ text-transform:uppercase;
+ width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+ background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+ position:absolute; /* position in the center of the screen */
+ left:50%;
+ top:50%;
+ height:50px; /* text area height */
+ width:225px; /* text area width */
+ text-align:center;
+ padding:180px 0px 0px 0px; /* image height is 200px (bottom 20px are overlapped with text) */
+ margin:-115px 0px 0px -112px; /* offset vertical: half of image height and text area height */
+ /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+ .app {
+ background-position:left center;
+ padding:75px 0px 75px 170px; /* padding-top + padding-bottom + text area = image height */
+ margin:-90px 0px 0px -198px; /* offset vertical: half of image height */
+ /* offset horizontal: half of image width and text area width */
+ }
+}
+
+h1 {
+ font-size:24px;
+ font-weight:normal;
+ margin:0px;
+ overflow:visible;
+ padding:0px;
+ text-align:center;
+}
+
+.event {
+ border-radius:4px;
+ -webkit-border-radius:4px;
+ color:#FFFFFF;
+ font-size:12px;
+ margin:0px 30px;
+ padding:2px 0px;
+}
+
+.event.listening {
+ background-color:#333333;
+ display:block;
+}
+
+.event.received {
+ background-color:#4B946A;
+ display:none;
+}
+
+@keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+@-webkit-keyframes fade {
+ from { opacity: 1.0; }
+ 50% { opacity: 0.4; }
+ to { opacity: 1.0; }
+}
+
+.blink {
+ animation:fade 3000ms infinite;
+ -webkit-animation:fade 3000ms infinite;
+}
--- /dev/null
+/*
+* jQuery Mobile Framework 1.1.1 1981b3f5ec22675ae47df8f0bdf9622e7780e90e
+* http://jquerymobile.com
+*
+* Copyright 2012 jQuery Foundation and other contributors
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+*/
+/* Swatches */
+/* A
+-----------------------------------------------------------------------------------------------------------*/
+.ui-bar-a {
+ border: 1px solid #333 /*{a-bar-border}*/;
+ background: #111111 /*{a-bar-background-color}*/;
+ color: #ffffff /*{a-bar-color}*/;
+ font-weight: bold;
+ text-shadow: 0 /*{a-bar-shadow-x}*/ -1px /*{a-bar-shadow-y}*/ 1px /*{a-bar-shadow-radius}*/ #000000 /*{a-bar-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #3c3c3c /*{a-bar-background-start}*/), to( #111 /*{a-bar-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/);
+}
+.ui-bar-a,
+.ui-bar-a input,
+.ui-bar-a select,
+.ui-bar-a textarea,
+.ui-bar-a button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-bar-a .ui-link-inherit {
+ color: #fff /*{a-bar-color}*/;
+}
+.ui-bar-a a.ui-link {
+ color: #7cc4e7 /*{a-bar-link-color}*/;
+ font-weight: bold;
+}
+.ui-bar-a a.ui-link:visited {
+ color: #2489CE /*{a-bar-link-visited}*/;
+}
+.ui-bar-a a.ui-link:hover {
+ color: #2489CE /*{a-bar-link-hover}*/;
+}
+.ui-bar-a a.ui-link:active {
+ color: #2489CE /*{a-bar-link-active}*/;
+}
+.ui-body-a,
+.ui-overlay-a {
+ border: 1px solid #444 /*{a-body-border}*/;
+ background: #222 /*{a-body-background-color}*/;
+ color: #fff /*{a-body-color}*/;
+ text-shadow: 0 /*{a-body-shadow-x}*/ 1px /*{a-body-shadow-y}*/ 1px /*{a-body-shadow-radius}*/ #111 /*{a-body-shadow-color}*/;
+ font-weight: normal;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #444 /*{a-body-background-start}*/), to( #222 /*{a-body-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/);
+}
+.ui-overlay-a {
+ background-image: none;
+ border-width: 0;
+}
+.ui-body-a,
+.ui-body-a input,
+.ui-body-a select,
+.ui-body-a textarea,
+.ui-body-a button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-a .ui-link-inherit {
+ color: #fff /*{a-body-color}*/;
+}
+.ui-body-a .ui-link {
+ color: #2489CE /*{a-body-link-color}*/;
+ font-weight: bold;
+}
+.ui-body-a .ui-link:visited {
+ color: #2489CE /*{a-body-link-visited}*/;
+}
+.ui-body-a .ui-link:hover {
+ color: #2489CE /*{a-body-link-hover}*/;
+}
+.ui-body-a .ui-link:active {
+ color: #2489CE /*{a-body-link-active}*/;
+}
+.ui-btn-up-a {
+ border: 1px solid #111 /*{a-bup-border}*/;
+ background: #333 /*{a-bup-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{a-bup-color}*/;
+ text-shadow: 0 /*{a-bup-shadow-x}*/ 1px /*{a-bup-shadow-y}*/ 1px /*{a-bup-shadow-radius}*/ #111 /*{a-bup-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #444444 /*{a-bup-background-start}*/), to( #2d2d2d /*{a-bup-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #444444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #444444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #444444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #444444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #444444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/);
+}
+.ui-btn-up-a:visited,
+.ui-btn-up-a a.ui-link-inherit {
+ color: #fff /*{a-bup-color}*/;
+}
+.ui-btn-hover-a {
+ border: 1px solid #000 /*{a-bhover-border}*/;
+ background: #444444 /*{a-bhover-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{a-bhover-color}*/;
+ text-shadow: 0 /*{a-bhover-shadow-x}*/ 1px /*{a-bhover-shadow-y}*/ 1px /*{a-bhover-shadow-radius}*/ #111 /*{a-bhover-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #555555 /*{a-bhover-background-start}*/), to( #383838 /*{a-bhover-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #555555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #555555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #555555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #555555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #555555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/);
+}
+.ui-btn-hover-a:visited,
+.ui-btn-hover-a:hover,
+.ui-btn-hover-a a.ui-link-inherit {
+ color: #fff /*{a-bhover-color}*/;
+}
+.ui-btn-down-a {
+ border: 1px solid #000 /*{a-bdown-border}*/;
+ background: #222 /*{a-bdown-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{a-bdown-color}*/;
+ text-shadow: 0 /*{a-bdown-shadow-x}*/ 1px /*{a-bdown-shadow-y}*/ 1px /*{a-bdown-shadow-radius}*/ #111 /*{a-bdown-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #202020 /*{a-bdown-background-start}*/), to( #2c2c2c /*{a-bdown-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/);
+}
+.ui-btn-down-a:visited,
+.ui-btn-down-a:hover,
+.ui-btn-down-a a.ui-link-inherit {
+ color: #fff /*{a-bdown-color}*/;
+}
+.ui-btn-up-a,
+.ui-btn-hover-a,
+.ui-btn-down-a {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+ text-decoration: none;
+}
+/* B
+-----------------------------------------------------------------------------------------------------------*/
+.ui-bar-b {
+ border: 1px solid #456f9a /*{b-bar-border}*/;
+ background: #5e87b0 /*{b-bar-background-color}*/;
+ color: #fff /*{b-bar-color}*/;
+ font-weight: bold;
+ text-shadow: 0 /*{b-bar-shadow-x}*/ 1px /*{b-bar-shadow-y}*/ 1px /*{b-bar-shadow-radius}*/ #3e6790 /*{b-bar-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bar-background-start}*/), to( #497bae /*{b-bar-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/);
+}
+.ui-bar-b,
+.ui-bar-b input,
+.ui-bar-b select,
+.ui-bar-b textarea,
+.ui-bar-b button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-bar-b .ui-link-inherit {
+ color: #fff /*{b-bar-color}*/;
+}
+.ui-bar-b a.ui-link {
+ color: #ddf0f8 /*{b-bar-link-color}*/;
+ font-weight: bold;
+}
+.ui-bar-b a.ui-link:visited {
+ color: #ddf0f8 /*{b-bar-link-visited}*/;
+}
+.ui-bar-b a.ui-link:hover {
+ color: #ddf0f8 /*{b-bar-link-hover}*/;
+}
+.ui-bar-b a.ui-link:active {
+ color: #ddf0f8 /*{b-bar-link-active}*/;
+}
+.ui-body-b,
+.ui-overlay-b {
+ border: 1px solid #999 /*{b-body-border}*/;
+ background: #f3f3f3 /*{b-body-background-color}*/;
+ color: #222222 /*{b-body-color}*/;
+ text-shadow: 0 /*{b-body-shadow-x}*/ 1px /*{b-body-shadow-y}*/ 0 /*{b-body-shadow-radius}*/ #fff /*{b-body-shadow-color}*/;
+ font-weight: normal;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{b-body-background-start}*/), to( #ccc /*{b-body-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/);
+}
+.ui-overlay-b {
+ background-image: none;
+ border-width: 0;
+}
+.ui-body-b,
+.ui-body-b input,
+.ui-body-b select,
+.ui-body-b textarea,
+.ui-body-b button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-b .ui-link-inherit {
+ color: #333333 /*{b-body-color}*/;
+}
+.ui-body-b .ui-link {
+ color: #2489CE /*{b-body-link-color}*/;
+ font-weight: bold;
+}
+.ui-body-b .ui-link:visited {
+ color: #2489CE /*{b-body-link-visited}*/;
+}
+.ui-body-b .ui-link:hover {
+ color: #2489CE /*{b-body-link-hover}*/;
+}
+.ui-body-b .ui-link:active {
+ color: #2489CE /*{b-body-link-active}*/;
+}
+.ui-btn-up-b {
+ border: 1px solid #044062 /*{b-bup-border}*/;
+ background: #396b9e /*{b-bup-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{b-bup-color}*/;
+ text-shadow: 0 /*{b-bup-shadow-x}*/ 1px /*{b-bup-shadow-y}*/ 1px /*{b-bup-shadow-radius}*/ #194b7e /*{b-bup-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #5f9cc5 /*{b-bup-background-start}*/), to( #396b9e /*{b-bup-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/);
+}
+.ui-btn-up-b:visited,
+.ui-btn-up-b a.ui-link-inherit {
+ color: #fff /*{b-bup-color}*/;
+}
+.ui-btn-hover-b {
+ border: 1px solid #00415e /*{b-bhover-border}*/;
+ background: #4b88b6 /*{b-bhover-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{b-bhover-color}*/;
+ text-shadow: 0 /*{b-bhover-shadow-x}*/ 1px /*{b-bhover-shadow-y}*/ 1px /*{b-bhover-shadow-radius}*/ #194b7e /*{b-bhover-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bhover-background-start}*/), to( #4272a4 /*{b-bhover-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/);
+}
+.ui-btn-hover-b:visited,
+.ui-btn-hover-a:hover,
+.ui-btn-hover-b a.ui-link-inherit {
+ color: #fff /*{b-bhover-color}*/;
+}
+.ui-btn-down-b {
+ border: 1px solid #225377 /*{b-bdown-border}*/;
+ background: #4e89c5 /*{b-bdown-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{b-bdown-color}*/;
+ text-shadow: 0 /*{b-bdown-shadow-x}*/ 1px /*{b-bdown-shadow-y}*/ 1px /*{b-bdown-shadow-radius}*/ #194b7e /*{b-bdown-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #295b8e /*{b-bdown-background-start}*/), to( #3e79b5 /*{b-bdown-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/);
+}
+.ui-btn-down-b:visited,
+.ui-btn-down-b:hover,
+.ui-btn-down-b a.ui-link-inherit {
+ color: #fff /*{b-bdown-color}*/;
+}
+.ui-btn-up-b,
+.ui-btn-hover-b,
+.ui-btn-down-b {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+ text-decoration: none;
+}
+/* C
+-----------------------------------------------------------------------------------------------------------*/
+.ui-bar-c {
+ border: 1px solid #B3B3B3 /*{c-bar-border}*/;
+ background: #eeeeee /*{c-bar-background-color}*/;
+ color: #3E3E3E /*{c-bar-color}*/;
+ font-weight: bold;
+ text-shadow: 0 /*{c-bar-shadow-x}*/ 1px /*{c-bar-shadow-y}*/ 1px /*{c-bar-shadow-radius}*/ #fff /*{c-bar-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{c-bar-background-start}*/), to( #ddd /*{c-bar-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/);
+}
+.ui-bar-c .ui-link-inherit {
+ color: #3E3E3E /*{c-bar-color}*/;
+}
+.ui-bar-c a.ui-link {
+ color: #7cc4e7 /*{c-bar-link-color}*/;
+ font-weight: bold;
+}
+.ui-bar-c a.ui-link:visited {
+ color: #2489CE /*{c-bar-link-visited}*/;
+}
+.ui-bar-c a.ui-link:hover {
+ color: #2489CE /*{c-bar-link-hover}*/;
+}
+.ui-bar-c a.ui-link:active {
+ color: #2489CE /*{c-bar-link-active}*/;
+}
+.ui-bar-c,
+.ui-bar-c input,
+.ui-bar-c select,
+.ui-bar-c textarea,
+.ui-bar-c button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-c,
+.ui-overlay-c {
+ border: 1px solid #aaa /*{c-body-border}*/;
+ color: #333333 /*{c-body-color}*/;
+ text-shadow: 0 /*{c-body-shadow-x}*/ 1px /*{c-body-shadow-y}*/ 0 /*{c-body-shadow-radius}*/ #fff /*{c-body-shadow-color}*/;
+ background: #f9f9f9 /*{c-body-background-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{c-body-background-start}*/), to( #eeeeee /*{c-body-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eeeeee /*{c-body-background-end}*/);
+}
+.ui-overlay-c {
+ background-image: none;
+ border-width: 0;
+}
+.ui-body-c,
+.ui-body-c input,
+.ui-body-c select,
+.ui-body-c textarea,
+.ui-body-c button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-c .ui-link-inherit {
+ color: #333333 /*{c-body-color}*/;
+}
+.ui-body-c .ui-link {
+ color: #2489CE /*{c-body-link-color}*/;
+ font-weight: bold;
+}
+.ui-body-c .ui-link:visited {
+ color: #2489CE /*{c-body-link-visited}*/;
+}
+.ui-body-c .ui-link:hover {
+ color: #2489CE /*{c-body-link-hover}*/;
+}
+.ui-body-c .ui-link:active {
+ color: #2489CE /*{c-body-link-active}*/;
+}
+.ui-btn-up-c {
+ border: 1px solid #ccc /*{c-bup-border}*/;
+ background: #eee /*{c-bup-background-color}*/;
+ font-weight: bold;
+ color: #222 /*{c-bup-color}*/;
+ text-shadow: 0 /*{c-bup-shadow-x}*/ 1px /*{c-bup-shadow-y}*/ 0 /*{c-bup-shadow-radius}*/ #ffffff /*{c-bup-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #ffffff /*{c-bup-background-start}*/), to( #f1f1f1 /*{c-bup-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #ffffff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/);
+}
+.ui-btn-up-c:visited,
+.ui-btn-up-c a.ui-link-inherit {
+ color: #2F3E46 /*{c-bup-color}*/;
+}
+.ui-btn-hover-c {
+ border: 1px solid #bbb /*{c-bhover-border}*/;
+ background: #dfdfdf /*{c-bhover-background-color}*/;
+ font-weight: bold;
+ color: #222 /*{c-bhover-color}*/;
+ text-shadow: 0 /*{c-bhover-shadow-x}*/ 1px /*{c-bhover-shadow-y}*/ 0 /*{c-bhover-shadow-radius}*/ #ffffff /*{c-bhover-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{c-bhover-background-start}*/), to( #e0e0e0 /*{c-bhover-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/);
+}
+.ui-btn-hover-c:visited,
+.ui-btn-hover-c:hover,
+.ui-btn-hover-c a.ui-link-inherit {
+ color: #2F3E46 /*{c-bhover-color}*/;
+}
+.ui-btn-down-c {
+ border: 1px solid #bbb /*{c-bdown-border}*/;
+ background: #d6d6d6 /*{c-bdown-background-color}*/;
+ font-weight: bold;
+ color: #222 /*{c-bdown-color}*/;
+ text-shadow: 0 /*{c-bdown-shadow-x}*/ 1px /*{c-bdown-shadow-y}*/ 0 /*{c-bdown-shadow-radius}*/ #ffffff /*{c-bdown-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{c-bdown-background-start}*/), to( #dfdfdf /*{c-bdown-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/);
+}
+.ui-btn-down-c:visited,
+.ui-btn-down-c:hover,
+.ui-btn-down-c a.ui-link-inherit {
+ color: #2F3E46 /*{c-bdown-color}*/;
+}
+.ui-btn-up-c,
+.ui-btn-hover-c,
+.ui-btn-down-c {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+ text-decoration: none;
+}
+/* D
+-----------------------------------------------------------------------------------------------------------*/
+.ui-bar-d {
+ border: 1px solid #bbb /*{d-bar-border}*/;
+ background: #bbb /*{d-bar-background-color}*/;
+ color: #333 /*{d-bar-color}*/;
+ text-shadow: 0 /*{d-bar-shadow-x}*/ 1px /*{d-bar-shadow-y}*/ 0 /*{d-bar-shadow-radius}*/ #eee /*{d-bar-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{d-bar-background-start}*/), to( #bbb /*{d-bar-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/);
+}
+.ui-bar-d,
+.ui-bar-d input,
+.ui-bar-d select,
+.ui-bar-d textarea,
+.ui-bar-d button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-bar-d .ui-link-inherit {
+ color: #333333 /*{d-bar-color}*/;
+}
+.ui-bar-d a.ui-link {
+ color: #2489CE /*{d-bar-link-color}*/;
+ font-weight: bold;
+}
+.ui-bar-d a.ui-link:visited {
+ color: #2489CE /*{d-bar-link-visited}*/;
+}
+.ui-bar-d a.ui-link:hover {
+ color: #2489CE /*{d-bar-link-hover}*/;
+}
+.ui-bar-d a.ui-link:active {
+ color: #2489CE /*{d-bar-link-active}*/;
+}
+.ui-body-d,
+.ui-overlay-d {
+ border: 1px solid #bbb /*{d-body-border}*/;
+ color: #333333 /*{d-body-color}*/;
+ text-shadow: 0 /*{d-body-shadow-x}*/ 1px /*{d-body-shadow-y}*/ 0 /*{d-body-shadow-radius}*/ #fff /*{d-body-shadow-color}*/;
+ background: #ffffff /*{d-body-background-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #fff), to( #fff /*{d-body-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/);
+}
+.ui-overlay-d {
+ background-image: none;
+ border-width: 0;
+}
+.ui-body-d,
+.ui-body-d input,
+.ui-body-d select,
+.ui-body-d textarea,
+.ui-body-d button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-d .ui-link-inherit {
+ color: #333333 /*{d-body-color}*/;
+}
+.ui-body-d .ui-link {
+ color: #2489CE /*{d-body-link-color}*/;
+ font-weight: bold;
+}
+.ui-body-d .ui-link:visited {
+ color: #2489CE /*{d-body-link-visited}*/;
+}
+.ui-body-d .ui-link:hover {
+ color: #2489CE /*{d-body-link-hover}*/;
+}
+.ui-body-d .ui-link:active {
+ color: #2489CE /*{d-body-link-active}*/;
+}
+.ui-btn-up-d {
+ border: 1px solid #bbb /*{d-bup-border}*/;
+ background: #fff /*{d-bup-background-color}*/;
+ font-weight: bold;
+ color: #333 /*{d-bup-color}*/;
+ text-shadow: 0 /*{d-bup-shadow-x}*/ 1px /*{d-bup-shadow-y}*/ 0 /*{d-bup-shadow-radius}*/ #fff /*{d-bup-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #fafafa), to( #f6f6f6 /*{d-bup-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/);
+}
+.ui-btn-up-d:visited,
+.ui-btn-up-d a.ui-link-inherit {
+ color: #333 /*{d-bup-color}*/;
+}
+.ui-btn-hover-d {
+ border: 1px solid #aaa /*{d-bhover-border}*/;
+ background: #eeeeee /*{d-bhover-background-color}*/;
+ font-weight: bold;
+ color: #333 /*{d-bhover-color}*/;
+ cursor: pointer;
+ text-shadow: 0 /*{d-bhover-shadow-x}*/ 1px /*{d-bhover-shadow-y}*/ 0 /*{d-bhover-shadow-radius}*/ #fff /*{d-bhover-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #eee), to( #fff /*{d-bhover-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/);
+}
+.ui-btn-hover-d:visited,
+.ui-btn-hover-d:hover,
+.ui-btn-hover-d a.ui-link-inherit {
+ color: #333 /*{d-bhover-color}*/;
+}
+.ui-btn-down-d {
+ border: 1px solid #aaa /*{d-bdown-border}*/;
+ background: #eee /*{d-bdown-background-color}*/;
+ font-weight: bold;
+ color: #333 /*{d-bdown-color}*/;
+ text-shadow: 0 /*{d-bdown-shadow-x}*/ 1px /*{d-bdown-shadow-y}*/ 0 /*{d-bdown-shadow-radius}*/ #ffffff /*{d-bdown-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #e5e5e5 /*{d-bdown-background-start}*/), to( #f2f2f2 /*{d-bdown-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/);
+}
+.ui-btn-down-d:visited,
+.ui-btn-down-d:hover,
+.ui-btn-down-d a.ui-link-inherit {
+ color: #333 /*{d-bdown-color}*/;
+}
+.ui-btn-up-d,
+.ui-btn-hover-d,
+.ui-btn-down-d {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+ text-decoration: none;
+}
+/* E
+-----------------------------------------------------------------------------------------------------------*/
+.ui-bar-e {
+ border: 1px solid #F7C942 /*{e-bar-border}*/;
+ background: #fadb4e /*{e-bar-background-color}*/;
+ color: #333 /*{e-bar-color}*/;
+ text-shadow: 0 /*{e-bar-shadow-x}*/ 1px /*{e-bar-shadow-y}*/ 0 /*{e-bar-shadow-radius}*/ #fff /*{e-bar-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #fceda7 /*{e-bar-background-start}*/), to( #fbef7e /*{e-bar-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/);
+}
+.ui-bar-e,
+.ui-bar-e input,
+.ui-bar-e select,
+.ui-bar-e textarea,
+.ui-bar-e button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-bar-e .ui-link-inherit {
+ color: #333333 /*{e-bar-color}*/;
+}
+.ui-bar-e a.ui-link {
+ color: #2489CE /*{e-bar-link-color}*/;
+ font-weight: bold;
+}
+.ui-bar-e a.ui-link:visited {
+ color: #2489CE /*{e-bar-link-visited}*/;
+}
+.ui-bar-e a.ui-link:hover {
+ color: #2489CE /*{e-bar-link-hover}*/;
+}
+.ui-bar-e a.ui-link:active {
+ color: #2489CE /*{e-bar-link-active}*/;
+}
+.ui-body-e,
+.ui-overlay-e {
+ border: 1px solid #F7C942 /*{e-body-border}*/;
+ color: #222222 /*{e-body-color}*/;
+ text-shadow: 0 /*{e-body-shadow-x}*/ 1px /*{e-body-shadow-y}*/ 0 /*{e-body-shadow-radius}*/ #fff /*{e-body-shadow-color}*/;
+ background: #fff9df /*{e-body-background-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #fffadf /*{e-body-background-start}*/), to( #fff3a5 /*{e-body-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/);
+}
+.ui-overlay-e {
+ background-image: none;
+ border-width: 0;
+}
+.ui-body-e,
+.ui-body-e input,
+.ui-body-e select,
+.ui-body-e textarea,
+.ui-body-e button {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-body-e .ui-link-inherit {
+ color: #333333 /*{e-body-color}*/;
+}
+.ui-body-e .ui-link {
+ color: #2489CE /*{e-body-link-color}*/;
+ font-weight: bold;
+}
+.ui-body-e .ui-link:visited {
+ color: #2489CE /*{e-body-link-visited}*/;
+}
+.ui-body-e .ui-link:hover {
+ color: #2489CE /*{e-body-link-hover}*/;
+}
+.ui-body-e .ui-link:active {
+ color: #2489CE /*{e-body-link-active}*/;
+}
+.ui-btn-up-e {
+ border: 1px solid #F4C63f /*{e-bup-border}*/;
+ background: #fadb4e /*{e-bup-background-color}*/;
+ font-weight: bold;
+ color: #222 /*{e-bup-color}*/;
+ text-shadow: 0 /*{e-bup-shadow-x}*/ 1px /*{e-bup-shadow-y}*/ 0 /*{e-bup-shadow-radius}*/ #fff /*{e-bup-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #ffefaa /*{e-bup-background-start}*/), to( #ffe155 /*{e-bup-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/);
+}
+.ui-btn-up-e:visited,
+.ui-btn-up-e a.ui-link-inherit {
+ color: #222 /*{e-bup-color}*/;
+}
+.ui-btn-hover-e {
+ border: 1px solid #F2C43d /*{e-bhover-border}*/;
+ background: #fbe26f /*{e-bhover-background-color}*/;
+ font-weight: bold;
+ color: #111 /*{e-bhover-color}*/;
+ text-shadow: 0 /*{e-bhover-shadow-x}*/ 1px /*{e-bhover-shadow-y}*/ 0 /*{e-bhover-shadow-radius}*/ #fff /*{e-bhover-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #fff5ba /*{e-bhover-background-start}*/), to( #fbdd52 /*{e-bhover-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/);
+}
+.ui-btn-hover-e:visited,
+.ui-btn-hover-e:hover,
+.ui-btn-hover-e a.ui-link-inherit {
+ color: #333 /*{e-bhover-color}*/;
+}
+.ui-btn-down-e {
+ border: 1px solid #F2C43d /*{e-bdown-border}*/;
+ background: #fceda7 /*{e-bdown-background-color}*/;
+ font-weight: bold;
+ color: #111 /*{e-bdown-color}*/;
+ text-shadow: 0 /*{e-bdown-shadow-x}*/ 1px /*{e-bdown-shadow-y}*/ 0 /*{e-bdown-shadow-radius}*/ #ffffff /*{e-bdown-shadow-color}*/;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #f8d94c /*{e-bdown-background-start}*/), to( #fadb4e /*{e-bdown-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/);
+}
+.ui-btn-down-e:visited,
+.ui-btn-down-e:hover,
+.ui-btn-down-e a.ui-link-inherit {
+ color: #333 /*{e-bdown-color}*/;
+}
+.ui-btn-up-e,
+.ui-btn-hover-e,
+.ui-btn-down-e {
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+ text-decoration: none;
+}
+/* Structure */
+/* links within "buttons"
+-----------------------------------------------------------------------------------------------------------*/
+a.ui-link-inherit {
+ text-decoration: none !important;
+}
+/* Active class used as the "on" state across all themes
+-----------------------------------------------------------------------------------------------------------*/
+.ui-btn-active {
+ border: 1px solid #2373a5 /*{global-active-border}*/;
+ background: #5393c5 /*{global-active-background-color}*/;
+ font-weight: bold;
+ color: #fff /*{global-active-color}*/;
+ cursor: pointer;
+ text-shadow: 0 /*{global-active-shadow-x}*/ 1px /*{global-active-shadow-y}*/ 1px /*{global-active-shadow-radius}*/ #3373a5 /*{global-active-shadow-color}*/;
+ text-decoration: none;
+ background-image: -webkit-gradient(linear, left top, left bottom, from( #5393c5 /*{global-active-background-start}*/), to( #6facd5 /*{global-active-background-end}*/)); /* Saf4+, Chrome */
+ background-image: -webkit-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Chrome 10+, Saf5.1+ */
+ background-image: -moz-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* FF3.6 */
+ background-image: -ms-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* IE10 */
+ background-image: -o-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Opera 11.10+ */
+ background-image: linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/);
+ font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
+}
+.ui-btn-active:visited,
+.ui-btn-active:hover,
+.ui-btn-active a.ui-link-inherit {
+ color: #fff /*{global-active-color}*/;
+}
+/* button inner top highlight
+-----------------------------------------------------------------------------------------------------------*/
+.ui-btn-inner {
+ border-top: 1px solid #fff;
+ border-color: rgba(255,255,255,.3);
+}
+/* corner rounding classes
+-----------------------------------------------------------------------------------------------------------*/
+.ui-corner-tl {
+ -moz-border-radius-topleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/;
+ border-top-left-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-tr {
+ -moz-border-radius-topright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/;
+ border-top-right-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-bl {
+ -moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-br {
+ -moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-top {
+ -moz-border-radius-topleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/;
+ border-top-left-radius: .6em /*{global-radii-blocks}*/;
+ -moz-border-radius-topright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/;
+ border-top-right-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-bottom {
+ -moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+ -moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+ }
+.ui-corner-right {
+ -moz-border-radius-topright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-right-radius: .6em /*{global-radii-blocks}*/;
+ border-top-right-radius: .6em /*{global-radii-blocks}*/;
+ -moz-border-radius-bottomright: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-right-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-left {
+ -moz-border-radius-topleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-top-left-radius: .6em /*{global-radii-blocks}*/;
+ border-top-left-radius: .6em /*{global-radii-blocks}*/;
+ -moz-border-radius-bottomleft: .6em /*{global-radii-blocks}*/;
+ -webkit-border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+ border-bottom-left-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-all {
+ -moz-border-radius: .6em /*{global-radii-blocks}*/;
+ -webkit-border-radius: .6em /*{global-radii-blocks}*/;
+ border-radius: .6em /*{global-radii-blocks}*/;
+}
+.ui-corner-none {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+}
+/* Form field separator
+-----------------------------------------------------------------------------------------------------------*/
+.ui-br {
+ border-bottom: rgb(130,130,130);
+ border-bottom: rgba(130,130,130,.3);
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+/* Interaction cues
+-----------------------------------------------------------------------------------------------------------*/
+.ui-disabled {
+ opacity: .3;
+}
+.ui-disabled,
+.ui-disabled a {
+ cursor: default !important;
+ pointer-events: none;
+}
+.ui-disabled .ui-btn-text {
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=30)";
+ filter: alpha(opacity=30);
+ zoom: 1;
+}
+/* Icons
+-----------------------------------------------------------------------------------------------------------*/
+.ui-icon,
+.ui-icon-searchfield:after {
+ background: #666 /*{global-icon-color}*/;
+ background: rgba(0,0,0,.4) /*{global-icon-disc}*/;
+ background-image: url(../images/icons-18-white.png) /*{global-icon-set}*/;
+ background-repeat: no-repeat;
+ -moz-border-radius: 9px;
+ -webkit-border-radius: 9px;
+ border-radius: 9px;
+}
+/* Alt icon color
+-----------------------------------------------------------------------------------------------------------*/
+.ui-icon-alt {
+ background: #fff;
+ background: rgba(255,255,255,.3);
+ background-image: url(images/icons-18-black.png);
+ background-repeat: no-repeat;
+}
+/* HD/"retina" sprite
+-----------------------------------------------------------------------------------------------------------*/
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
+ only screen and (min--moz-device-pixel-ratio: 1.5),
+ only screen and (min-resolution: 240dpi) {
+
+ .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
+ .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
+ .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
+ .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-search, .ui-icon-searchfield:after,
+ .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
+ background-image: url(images/icons-36-white.png);
+ -moz-background-size: 776px 18px;
+ -o-background-size: 776px 18px;
+ -webkit-background-size: 776px 18px;
+ background-size: 776px 18px;
+ }
+ .ui-icon-alt {
+ background-image: url(images/icons-36-black.png);
+ }
+}
+/* plus minus */
+.ui-icon-plus {
+ background-position: -0 50%;
+}
+.ui-icon-minus {
+ background-position: -36px 50%;
+}
+/* delete/close */
+.ui-icon-delete {
+ background-position: -72px 50%;
+}
+/* arrows */
+.ui-icon-arrow-r {
+ background-position: -108px 50%;
+}
+.ui-icon-arrow-l {
+ background-position: -144px 50%;
+}
+.ui-icon-arrow-u {
+ background-position: -180px 50%;
+}
+.ui-icon-arrow-d {
+ background-position: -216px 50%;
+}
+/* misc */
+.ui-icon-check {
+ background-position: -252px 50%;
+}
+.ui-icon-gear {
+ background-position: -288px 50%;
+}
+.ui-icon-refresh {
+ background-position: -324px 50%;
+}
+.ui-icon-forward {
+ background-position: -360px 50%;
+}
+.ui-icon-back {
+ background-position: -396px 50%;
+}
+.ui-icon-grid {
+ background-position: -432px 50%;
+}
+.ui-icon-star {
+ background-position: -468px 50%;
+}
+.ui-icon-alert {
+ background-position: -504px 50%;
+}
+.ui-icon-info {
+ background-position: -540px 50%;
+}
+.ui-icon-home {
+ background-position: -576px 50%;
+}
+.ui-icon-search,
+.ui-icon-searchfield:after {
+ background-position: -612px 50%;
+}
+.ui-icon-checkbox-off {
+ background-position: -684px 50%;
+}
+.ui-icon-checkbox-on {
+ background-position: -648px 50%;
+}
+.ui-icon-radio-off {
+ background-position: -756px 50%;
+}
+.ui-icon-radio-on {
+ background-position: -720px 50%;
+}
+/* checks,radios */
+.ui-checkbox .ui-icon {
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+.ui-icon-checkbox-off,
+.ui-icon-radio-off {
+ background-color: transparent;
+}
+.ui-checkbox-on .ui-icon,
+.ui-radio-on .ui-icon {
+ background-color: #4596ce /*{global-active-background-color}*/; /* NOTE: this hex should match the active state color. It's repeated here for cascade */
+}
+/* loading icon */
+.ui-icon-loading {
+ background: url(images/ajax-loader.gif);
+ background-size: 46px 46px;
+}
+/* Button corner classes
+-----------------------------------------------------------------------------------------------------------*/
+.ui-btn-corner-tl {
+ -moz-border-radius-topleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/;
+ border-top-left-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-tr {
+ -moz-border-radius-topright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/;
+ border-top-right-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-bl {
+ -moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-br {
+ -moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-top {
+ -moz-border-radius-topleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/;
+ border-top-left-radius: 1em /*{global-radii-buttons}*/;
+ -moz-border-radius-topright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/;
+ border-top-right-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-bottom {
+ -moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+ -moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-right {
+ -moz-border-radius-topright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-right-radius: 1em /*{global-radii-buttons}*/;
+ border-top-right-radius: 1em /*{global-radii-buttons}*/;
+ -moz-border-radius-bottomright: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-right-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-left {
+ -moz-border-radius-topleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-top-left-radius: 1em /*{global-radii-buttons}*/;
+ border-top-left-radius: 1em /*{global-radii-buttons}*/;
+ -moz-border-radius-bottomleft: 1em /*{global-radii-buttons}*/;
+ -webkit-border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+ border-bottom-left-radius: 1em /*{global-radii-buttons}*/;
+}
+.ui-btn-corner-all {
+ -moz-border-radius: 1em /*{global-radii-buttons}*/;
+ -webkit-border-radius: 1em /*{global-radii-buttons}*/;
+ border-radius: 1em /*{global-radii-buttons}*/;
+}
+/* radius clip workaround for cleaning up corner trapping */
+.ui-corner-tl,
+.ui-corner-tr,
+.ui-corner-bl,
+.ui-corner-br,
+.ui-corner-top,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-left,
+.ui-corner-all,
+.ui-btn-corner-tl,
+.ui-btn-corner-tr,
+.ui-btn-corner-bl,
+.ui-btn-corner-br,
+.ui-btn-corner-top,
+.ui-btn-corner-bottom,
+.ui-btn-corner-right,
+.ui-btn-corner-left,
+.ui-btn-corner-all {
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+}
+/* Overlay / modal
+-----------------------------------------------------------------------------------------------------------*/
+.ui-overlay {
+ background: #666;
+ opacity: .5;
+ filter: Alpha(Opacity=50);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+.ui-overlay-shadow {
+ -moz-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+ -webkit-box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+ box-shadow: 0px 0px 12px rgba(0,0,0,.6);
+}
+.ui-shadow {
+ -moz-box-shadow: 0px 1px 4px /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/;
+ -webkit-box-shadow: 0px 1px 4px /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/;
+ box-shadow: 0px 1px 4px /*{global-box-shadow-size}*/ rgba(0,0,0,.3) /*{global-box-shadow-color}*/;
+}
+.ui-bar-a .ui-shadow,
+.ui-bar-b .ui-shadow ,
+.ui-bar-c .ui-shadow {
+ -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+ -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+ box-shadow: 0px 1px 0 rgba(255,255,255,.3);
+}
+.ui-shadow-inset {
+ -moz-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+ -webkit-box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+ box-shadow: inset 0px 1px 4px rgba(0,0,0,.2);
+}
+.ui-icon-shadow {
+ -moz-box-shadow: 0px 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
+ -webkit-box-shadow: 0px 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
+ box-shadow: 0px 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
+}
+/* Focus state - set here for specificity (note: these classes are added by JavaScript)
+-----------------------------------------------------------------------------------------------------------*/
+.ui-btn:focus, .ui-link-inherit:focus {
+ outline: 0;
+}
+.ui-btn.ui-focus {
+ z-index: 1;
+}
+.ui-focus,
+.ui-btn:focus {
+ -moz-box-shadow: inset 0px 0px 3px #387bbe /*{global-active-background-color}*/, 0px 0px 9px #387bbe /*{global-active-background-color}*/;
+ -webkit-box-shadow: inset 0px 0px 3px #387bbe /*{global-active-background-color}*/, 0px 0px 9px #387bbe /*{global-active-background-color}*/;
+ box-shadow: inset 0px 0px 3px #387bbe /*{global-active-background-color}*/, 0px 0px 9px #387bbe /*{global-active-background-color}*/;
+}
+.ui-input-text.ui-focus,
+.ui-input-search.ui-focus {
+ -moz-box-shadow: 0px 0px 12px #387bbe /*{global-active-background-color}*/;
+ -webkit-box-shadow: 0px 0px 12px #387bbe /*{global-active-background-color}*/;
+ box-shadow: 0px 0px 12px #387bbe /*{global-active-background-color}*/;
+}
+/* unset box shadow in browsers that don't do it right
+-----------------------------------------------------------------------------------------------------------*/
+.ui-mobile-nosupport-boxshadow * {
+ -moz-box-shadow: none !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+}
+/* ...and bring back focus */
+.ui-mobile-nosupport-boxshadow .ui-focus,
+.ui-mobile-nosupport-boxshadow .ui-btn:focus,
+.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus {
+ outline-width: 1px;
+ outline-style: auto;
+}
+/* some unsets - more probably needed */
+.ui-mobile, .ui-mobile body { height: 99.9%; }
+.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }
+.ui-mobile a img, .ui-mobile fieldset { border-width: 0; }
+/* responsive page widths */
+.ui-mobile-viewport { margin: 0; overflow-x: visible; -webkit-text-size-adjust: none; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
+/* Issue #2066 */
+body.ui-mobile-viewport,
+div.ui-mobile-viewport { overflow-x: hidden; }
+/* "page" containers - full-screen views, one should always be in view post-pageload */
+.ui-mobile [data-role=page], .ui-mobile [data-role=dialog], .ui-page { top: 0; left: 0; width: 100%; min-height: 100%; position: absolute; display: none; border: 0; }
+.ui-mobile .ui-page-active { display: block; overflow: visible; }
+/* on ios4, setting focus on the page element causes flashing during transitions when there is an outline, so we turn off outlines */
+.ui-page { outline: none; }
+/*orientations from js are available */
+@media screen and (orientation: portrait){
+.ui-mobile, .ui-mobile .ui-page { min-height: 420px; }
+}
+@media screen and (orientation: landscape){
+.ui-mobile, .ui-mobile .ui-page { min-height: 300px; }
+}
+/* loading screen */
+.ui-loading .ui-loader { display: block; }
+.ui-loader { display: none; z-index: 9999999; position: fixed; top: 50%; left: 50%; border:0; }
+.ui-loader-default { background: none; opacity: .18; width: 46px; height: 46px; margin-left: -23px; margin-top: -23px; }
+.ui-loader-verbose { width: 200px; opacity: .88; box-shadow: 0 1px 1px -1px #fff; height: auto; margin-left: -110px; margin-top: -43px; padding: 10px; }
+.ui-loader-default h1 { font-size: 0; width: 0; height: 0; overflow: hidden; }
+.ui-loader-verbose h1 { font-size: 16px; margin: 0; text-align: center; }
+.ui-loader .ui-icon { background-color: #000; display: block; margin: 0; width: 44px; height: 44px; padding: 1px; -webkit-border-radius: 36px; -moz-border-radius: 36px; border-radius: 36px; }
+.ui-loader-verbose .ui-icon { margin: 0 auto 10px; opacity: .75; }
+.ui-loader-textonly { padding: 15px; margin-left: -115px; }
+.ui-loader-textonly .ui-icon { display: none; }
+.ui-loader-fakefix { position: absolute; }
+/*fouc*/
+.ui-mobile-rendering > * { visibility: hidden; }
+/*headers, content panels*/
+.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }
+.ui-bar { font-size: 16px; margin: 0; }
+.ui-bar h1, .ui-bar h2, .ui-bar h3, .ui-bar h4, .ui-bar h5, .ui-bar h6 { margin: 0; padding: 0; font-size: 16px; display: inline-block; }
+.ui-header, .ui-footer { position: relative; border-left-width: 0; border-right-width: 0; zoom: 1; }
+.ui-header .ui-btn-left,
+.ui-header .ui-btn-right,
+.ui-footer .ui-btn-left,
+.ui-footer .ui-btn-right { position: absolute; top: 3px; }
+.ui-header .ui-btn-left,
+.ui-footer .ui-btn-left { left: 5px; }
+.ui-header .ui-btn-right,
+.ui-footer .ui-btn-right { right: 5px; }
+.ui-footer .ui-btn-icon-notext,
+.ui-header .ui-btn-icon-notext { top: 6px; }
+.ui-header .ui-title, .ui-footer .ui-title { min-height: 1.1em; text-align: center; font-size: 16px; display: block; margin: .6em 30% .8em; padding: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; outline: 0 !important; }
+.ui-footer .ui-title { margin: .6em 15px .8em; }
+/*content area*/
+.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }
+/* icons sizing */
+.ui-icon { width: 18px; height: 18px; }
+/* non-js content hiding */
+.ui-nojs { position: absolute; left: -9999px; }
+/* accessible content hiding */
+.ui-hide-label label.ui-input-text, .ui-hide-label label.ui-select, .ui-hide-label label.ui-slider, .ui-hide-label label.ui-submit, .ui-hide-label .ui-controlgroup-label,
+.ui-hidden-accessible { position: absolute !important; left: -9999px; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+/* Transitions originally inspired by those from jQtouch, nice work, folks */
+.ui-mobile-viewport-transitioning,
+.ui-mobile-viewport-transitioning .ui-page {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.in {
+ -webkit-animation-timing-function: ease-out;
+ -webkit-animation-duration: 350ms;
+ -moz-animation-timing-function: ease-out;
+ -moz-animation-duration: 350ms;
+}
+.out {
+ -webkit-animation-timing-function: ease-in;
+ -webkit-animation-duration: 225ms;
+ -moz-animation-timing-function: ease-in;
+ -moz-animation-duration: 225;
+}
+@-webkit-keyframes fadein {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fadein {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fadeout {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fadeout {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+.fade.out {
+ opacity: 0;
+ -webkit-animation-duration: 125ms;
+ -webkit-animation-name: fadeout;
+ -moz-animation-duration: 125ms;
+ -moz-animation-name: fadeout;
+}
+.fade.in {
+ opacity: 1;
+ -webkit-animation-duration: 225ms;
+ -webkit-animation-name: fadein;
+ -moz-animation-duration: 225ms;
+ -moz-animation-name: fadein;
+}
+.pop {
+ -webkit-transform-origin: 50% 50%;
+ -moz-transform-origin: 50% 50%;
+}
+.pop.in {
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ opacity: 1;
+ -webkit-animation-name: popin;
+ -moz-animation-name: popin;
+ -webkit-animation-duration: 350ms;
+ -moz-animation-duration: 350ms;
+}
+.pop.out {
+ -webkit-animation-name: fadeout;
+ -moz-animation-name: fadeout;
+ opacity: 0;
+ -webkit-animation-duration: 100ms;
+ -moz-animation-duration: 100ms;
+}
+.pop.in.reverse {
+ -webkit-animation-name: fadein;
+ -moz-animation-name: fadein;
+}
+.pop.out.reverse {
+ -webkit-transform: scale(.8);
+ -moz-transform: scale(.8);
+ -webkit-animation-name: popout;
+ -moz-animation-name: popout;
+}
+@-webkit-keyframes popin {
+ from {
+ -webkit-transform: scale(.8);
+ opacity: 0;
+ }
+ to {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ }
+}
+@-moz-keyframes popin {
+ from {
+ -moz-transform: scale(.8);
+ opacity: 0;
+ }
+ to {
+ -moz-transform: scale(1);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes popout {
+ from {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ -webkit-transform: scale(.8);
+ opacity: 0;
+ }
+}
+@-moz-keyframes popout {
+ from {
+ -moz-transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ -moz-transform: scale(.8);
+ opacity: 0;
+ }
+}
+/* keyframes for slidein from sides */
+@-webkit-keyframes slideinfromright {
+ from { -webkit-transform: translateX(100%); }
+ to { -webkit-transform: translateX(0); }
+}
+@-moz-keyframes slideinfromright {
+ from { -moz-transform: translateX(100%); }
+ to { -moz-transform: translateX(0); }
+}
+@-webkit-keyframes slideinfromleft {
+ from { -webkit-transform: translateX(-100%); }
+ to { -webkit-transform: translateX(0); }
+}
+@-moz-keyframes slideinfromleft {
+ from { -moz-transform: translateX(-100%); }
+ to { -moz-transform: translateX(0); }
+}
+/* keyframes for slideout to sides */
+@-webkit-keyframes slideouttoleft {
+ from { -webkit-transform: translateX(0); }
+ to { -webkit-transform: translateX(-100%); }
+}
+@-moz-keyframes slideouttoleft {
+ from { -moz-transform: translateX(0); }
+ to { -moz-transform: translateX(-100%); }
+}
+@-webkit-keyframes slideouttoright {
+ from { -webkit-transform: translateX(0); }
+ to { -webkit-transform: translateX(100%); }
+}
+@-moz-keyframes slideouttoright {
+ from { -moz-transform: translateX(0); }
+ to { -moz-transform: translateX(100%); }
+}
+.slide.out, .slide.in {
+ -webkit-animation-timing-function: ease-out;
+ -webkit-animation-duration: 350ms;
+ -moz-animation-timing-function: ease-out;
+ -moz-animation-duration: 350ms;
+}
+.slide.out {
+ -webkit-transform: translateX(-100%);
+ -webkit-animation-name: slideouttoleft;
+ -moz-transform: translateX(-100%);
+ -moz-animation-name: slideouttoleft;
+}
+.slide.in {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: slideinfromright;
+ -moz-transform: translateX(0);
+ -moz-animation-name: slideinfromright;
+}
+.slide.out.reverse {
+ -webkit-transform: translateX(100%);
+ -webkit-animation-name: slideouttoright;
+ -moz-transform: translateX(100%);
+ -moz-animation-name: slideouttoright;
+}
+.slide.in.reverse {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: slideinfromleft;
+ -moz-transform: translateX(0);
+ -moz-animation-name: slideinfromleft;
+}
+.slidefade.out {
+ -webkit-transform: translateX(-100%);
+ -webkit-animation-name: slideouttoleft;
+ -moz-transform: translateX(-100%);
+ -moz-animation-name: slideouttoleft;
+ -webkit-animation-duration: 225ms;
+ -moz-animation-duration: 225ms;
+}
+.slidefade.in {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: fadein;
+ -moz-transform: translateX(0);
+ -moz-animation-name: fadein;
+ -webkit-animation-duration: 200ms;
+ -moz-animation-duration: 200ms;
+}
+.slidefade.out.reverse {
+ -webkit-transform: translateX(100%);
+ -webkit-animation-name: slideouttoright;
+ -moz-transform: translateX(100%);
+ -moz-animation-name: slideouttoright;
+ -webkit-animation-duration: 200ms;
+ -moz-animation-duration: 200ms;
+}
+.slidefade.in.reverse {
+ -webkit-transform: translateX(0);
+ -webkit-animation-name: fadein;
+ -moz-transform: translateX(0);
+ -moz-animation-name: fadein;
+ -webkit-animation-duration: 200ms;
+ -moz-animation-duration: 200ms;
+}
+/* slide down */
+.slidedown.out {
+ -webkit-animation-name: fadeout;
+ -moz-animation-name: fadeout;
+ -webkit-animation-duration: 100ms;
+ -moz-animation-duration: 100ms;
+}
+.slidedown.in {
+ -webkit-transform: translateY(0);
+ -webkit-animation-name: slideinfromtop;
+ -moz-transform: translateY(0);
+ -moz-animation-name: slideinfromtop;
+ -webkit-animation-duration: 250ms;
+ -moz-animation-duration: 250ms;
+}
+.slidedown.in.reverse {
+ -webkit-animation-name: fadein;
+ -moz-animation-name: fadein;
+ -webkit-animation-duration: 150ms;
+ -moz-animation-duration: 150ms;
+}
+.slidedown.out.reverse {
+ -webkit-transform: translateY(-100%);
+ -moz-transform: translateY(-100%);
+ -webkit-animation-name: slideouttotop;
+ -moz-animation-name: slideouttotop;
+ -webkit-animation-duration: 200ms;
+ -moz-animation-duration: 200ms;
+}
+@-webkit-keyframes slideinfromtop {
+ from { -webkit-transform: translateY(-100%); }
+ to { -webkit-transform: translateY(0); }
+}
+@-moz-keyframes slideinfromtop {
+ from { -moz-transform: translateY(-100%); }
+ to { -moz-transform: translateY(0); }
+}
+@-webkit-keyframes slideouttotop {
+ from { -webkit-transform: translateY(0); }
+ to { -webkit-transform: translateY(-100%); }
+}
+@-moz-keyframes slideouttotop {
+ from { -moz-transform: translateY(0); }
+ to { -moz-transform: translateY(-100%); }
+}
+/* slide up */
+.slideup.out {
+ -webkit-animation-name: fadeout;
+ -moz-animation-name: fadeout;
+ -webkit-animation-duration: 100ms;
+ -moz-animation-duration: 100ms;
+}
+.slideup.in {
+ -webkit-transform: translateY(0);
+ -webkit-animation-name: slideinfrombottom;
+ -moz-transform: translateY(0);
+ -moz-animation-name: slideinfrombottom;
+ -webkit-animation-duration: 250ms;
+ -moz-animation-duration: 250ms;
+}
+.slideup.in.reverse {
+ -webkit-animation-name: fadein;
+ -moz-animation-name: fadein;
+ -webkit-animation-duration: 150ms;
+ -moz-animation-duration: 150ms;
+}
+.slideup.out.reverse {
+ -webkit-transform: translateY(100%);
+ -moz-transform: translateY(100%);
+ -webkit-animation-name: slideouttobottom;
+ -moz-animation-name: slideouttobottom;
+ -webkit-animation-duration: 200ms;
+ -moz-animation-duration: 200ms;
+}
+@-webkit-keyframes slideinfrombottom {
+ from { -webkit-transform: translateY(100%); }
+ to { -webkit-transform: translateY(0); }
+}
+@-moz-keyframes slideinfrombottom {
+ from { -moz-transform: translateY(100%); }
+ to { -moz-transform: translateY(0); }
+}
+@-webkit-keyframes slideouttobottom {
+ from { -webkit-transform: translateY(0); }
+ to { -webkit-transform: translateY(100%); }
+}
+@-moz-keyframes slideouttobottom {
+ from { -moz-transform: translateY(0); }
+ to { -moz-transform: translateY(100%); }
+}
+/* The properties in this rule are only necessary for the 'flip' transition.
+ * We need specify the perspective to create a projection matrix. This will add
+ * some depth as the element flips. The depth number represents the distance of
+ * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
+ * value.
+ */
+.viewport-flip {
+ -webkit-perspective: 1000;
+ -moz-perspective: 1000;
+ position: absolute;
+}
+.flip {
+ -webkit-backface-visibility:hidden;
+ -webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
+ -moz-backface-visibility:hidden;
+ -moz-transform:translateX(0);
+}
+.flip.out {
+ -webkit-transform: rotateY(-90deg) scale(.9);
+ -webkit-animation-name: flipouttoleft;
+ -webkit-animation-duration: 175ms;
+ -moz-transform: rotateY(-90deg) scale(.9);
+ -moz-animation-name: flipouttoleft;
+ -moz-animation-duration: 175ms;
+}
+.flip.in {
+ -webkit-animation-name: flipintoright;
+ -webkit-animation-duration: 225ms;
+ -moz-animation-name: flipintoright;
+ -moz-animation-duration: 225ms;
+}
+.flip.out.reverse {
+ -webkit-transform: rotateY(90deg) scale(.9);
+ -webkit-animation-name: flipouttoright;
+ -moz-transform: rotateY(90deg) scale(.9);
+ -moz-animation-name: flipouttoright;
+}
+.flip.in.reverse {
+ -webkit-animation-name: flipintoleft;
+ -moz-animation-name: flipintoleft;
+}
+@-webkit-keyframes flipouttoleft {
+ from { -webkit-transform: rotateY(0); }
+ to { -webkit-transform: rotateY(-90deg) scale(.9); }
+}
+@-moz-keyframes flipouttoleft {
+ from { -moz-transform: rotateY(0); }
+ to { -moz-transform: rotateY(-90deg) scale(.9); }
+}
+@-webkit-keyframes flipouttoright {
+ from { -webkit-transform: rotateY(0) ; }
+ to { -webkit-transform: rotateY(90deg) scale(.9); }
+}
+@-moz-keyframes flipouttoright {
+ from { -moz-transform: rotateY(0); }
+ to { -moz-transform: rotateY(90deg) scale(.9); }
+}
+@-webkit-keyframes flipintoleft {
+ from { -webkit-transform: rotateY(-90deg) scale(.9); }
+ to { -webkit-transform: rotateY(0); }
+}
+@-moz-keyframes flipintoleft {
+ from { -moz-transform: rotateY(-90deg) scale(.9); }
+ to { -moz-transform: rotateY(0); }
+}
+@-webkit-keyframes flipintoright {
+ from { -webkit-transform: rotateY(90deg) scale(.9); }
+ to { -webkit-transform: rotateY(0); }
+}
+@-moz-keyframes flipintoright {
+ from { -moz-transform: rotateY(90deg) scale(.9); }
+ to { -moz-transform: rotateY(0); }
+}
+/* The properties in this rule are only necessary for the 'flip' transition.
+ * We need specify the perspective to create a projection matrix. This will add
+ * some depth as the element flips. The depth number represents the distance of
+ * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
+ * value.
+ */
+.viewport-turn {
+ -webkit-perspective: 1000;
+ -moz-perspective: 1000;
+ position: absolute;
+}
+.turn {
+ -webkit-backface-visibility:hidden;
+ -webkit-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
+ -webkit-transform-origin: 0;
+
+ -moz-backface-visibility:hidden;
+ -moz-transform:translateX(0); /* Needed to work around an iOS 3.1 bug that causes listview thumbs to disappear when -webkit-visibility:hidden is used. */
+ -moz-transform-origin: 0;
+}
+.turn.out {
+ -webkit-transform: rotateY(-90deg) scale(.9);
+ -webkit-animation-name: flipouttoleft;
+ -moz-transform: rotateY(-90deg) scale(.9);
+ -moz-animation-name: flipouttoleft;
+ -webkit-animation-duration: 125ms;
+ -moz-animation-duration: 125ms;
+}
+.turn.in {
+ -webkit-animation-name: flipintoright;
+ -moz-animation-name: flipintoright;
+ -webkit-animation-duration: 250ms;
+ -moz-animation-duration: 250ms;
+
+}
+.turn.out.reverse {
+ -webkit-transform: rotateY(90deg) scale(.9);
+ -webkit-animation-name: flipouttoright;
+ -moz-transform: rotateY(90deg) scale(.9);
+ -moz-animation-name: flipouttoright;
+}
+.turn.in.reverse {
+ -webkit-animation-name: flipintoleft;
+ -moz-animation-name: flipintoleft;
+}
+@-webkit-keyframes flipouttoleft {
+ from { -webkit-transform: rotateY(0); }
+ to { -webkit-transform: rotateY(-90deg) scale(.9); }
+}
+@-moz-keyframes flipouttoleft {
+ from { -moz-transform: rotateY(0); }
+ to { -moz-transform: rotateY(-90deg) scale(.9); }
+}
+@-webkit-keyframes flipouttoright {
+ from { -webkit-transform: rotateY(0) ; }
+ to { -webkit-transform: rotateY(90deg) scale(.9); }
+}
+@-moz-keyframes flipouttoright {
+ from { -moz-transform: rotateY(0); }
+ to { -moz-transform: rotateY(90deg) scale(.9); }
+}
+@-webkit-keyframes flipintoleft {
+ from { -webkit-transform: rotateY(-90deg) scale(.9); }
+ to { -webkit-transform: rotateY(0); }
+}
+@-moz-keyframes flipintoleft {
+ from { -moz-transform: rotateY(-90deg) scale(.9); }
+ to { -moz-transform: rotateY(0); }
+}
+@-webkit-keyframes flipintoright {
+ from { -webkit-transform: rotateY(90deg) scale(.9); }
+ to { -webkit-transform: rotateY(0); }
+}
+@-moz-keyframes flipintoright {
+ from { -moz-transform: rotateY(90deg) scale(.9); }
+ to { -moz-transform: rotateY(0); }
+}
+/* flow transition */
+.flow {
+ -webkit-transform-origin: 50% 30%;
+ -moz-transform-origin: 50% 30%;
+ -webkit-box-shadow: 0 0 20px rgba(0,0,0,.4);
+ -moz-box-shadow: 0 0 20px rgba(0,0,0,.4);
+}
+.ui-dialog.flow {
+ -webkit-transform-origin: none;
+ -moz-transform-origin: none;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+}
+.flow.out {
+ -webkit-transform: translateX(-100%) scale(.7);
+ -webkit-animation-name: flowouttoleft;
+ -webkit-animation-timing-function: ease;
+ -webkit-animation-duration: 350ms;
+ -moz-transform: translateX(-100%) scale(.7);
+ -moz-animation-name: flowouttoleft;
+ -moz-animation-timing-function: ease;
+ -moz-animation-duration: 350ms;
+}
+.flow.in {
+ -webkit-transform: translateX(0) scale(1);
+ -webkit-animation-name: flowinfromright;
+ -webkit-animation-timing-function: ease;
+ -webkit-animation-duration: 350ms;
+ -moz-transform: translateX(0) scale(1);
+ -moz-animation-name: flowinfromright;
+ -moz-animation-timing-function: ease;
+ -moz-animation-duration: 350ms;
+}
+.flow.out.reverse {
+ -webkit-transform: translateX(100%);
+ -webkit-animation-name: flowouttoright;
+ -moz-transform: translateX(100%);
+ -moz-animation-name: flowouttoright;
+}
+.flow.in.reverse {
+ -webkit-animation-name: flowinfromleft;
+ -moz-animation-name: flowinfromleft;
+}
+@-webkit-keyframes flowouttoleft {
+ 0% { -webkit-transform: translateX(0) scale(1); }
+ 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
+ 100% { -webkit-transform: translateX(-100%) scale(.7); }
+}
+@-moz-keyframes flowouttoleft {
+ 0% { -moz-transform: translateX(0) scale(1); }
+ 60%, 70% { -moz-transform: translateX(0) scale(.7); }
+ 100% { -moz-transform: translateX(-100%) scale(.7); }
+}
+@-webkit-keyframes flowouttoright {
+ 0% { -webkit-transform: translateX(0) scale(1); }
+ 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
+ 100% { -webkit-transform: translateX(100%) scale(.7); }
+}
+@-moz-keyframes flowouttoright {
+ 0% { -moz-transform: translateX(0) scale(1); }
+ 60%, 70% { -moz-transform: translateX(0) scale(.7); }
+ 100% { -moz-transform: translateX(100%) scale(.7); }
+}
+@-webkit-keyframes flowinfromleft {
+ 0% { -webkit-transform: translateX(-100%) scale(.7); }
+ 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
+ 100% { -webkit-transform: translateX(0) scale(1); }
+}
+@-moz-keyframes flowinfromleft {
+ 0% { -moz-transform: translateX(-100%) scale(.7); }
+ 30%, 40% { -moz-transform: translateX(0) scale(.7); }
+ 100% { -moz-transform: translateX(0) scale(1); }
+}
+@-webkit-keyframes flowinfromright {
+ 0% { -webkit-transform: translateX(100%) scale(.7); }
+ 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
+ 100% { -webkit-transform: translateX(0) scale(1); }
+}
+@-moz-keyframes flowinfromright {
+ 0% { -moz-transform: translateX(100%) scale(.7); }
+ 30%, 40% { -moz-transform: translateX(0) scale(.7); }
+ 100% { -moz-transform: translateX(0) scale(1); }
+}
+/* content configurations. */
+.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }
+.ui-block-a, .ui-block-b, .ui-block-c, .ui-block-d, .ui-block-e { margin: 0; padding: 0; border: 0; float: left; min-height: 1px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
+/* grid solo: 100 - single item fallback */
+.ui-grid-solo .ui-block-a { display: block; float: none; }
+/* Lower percentages for older browsers (i.e. IE7) to prevent wrapping. -.5px to fix BB5 wrap issue. */
+/* grid a: 50/50 */
+.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 49.95%; }
+.ui-grid-a > :nth-child(n) { width: 50%; margin-right: -.5px; }
+.ui-grid-a .ui-block-a { clear: left; padding-right:3px;}
+/* grid b: 33/33/33 */
+.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.25%; }
+.ui-grid-b > :nth-child(n) { width: 33.333%; margin-right: -.5px; }
+.ui-grid-b .ui-block-a { clear: left; }
+/* grid c: 25/25/25/25 */
+.ui-grid-c .ui-block-a, .ui-grid-c .ui-block-b, .ui-grid-c .ui-block-c, .ui-grid-c .ui-block-d { width: 24.925%; }
+.ui-grid-c > :nth-child(n) { width: 25%; margin-right: -.5px; }
+.ui-grid-c .ui-block-a { clear: left; }
+/* grid d: 20/20/20/20/20 */
+.ui-grid-d .ui-block-a, .ui-grid-d .ui-block-b, .ui-grid-d .ui-block-c, .ui-grid-d .ui-block-d, .ui-grid-d .ui-block-e { width: 19.925%; }
+.ui-grid-d > :nth-child(n) { width: 20%; }
+.ui-grid-d .ui-block-a { clear: left; }
+/* fixed page header & footer configuration */
+.ui-header-fixed,
+.ui-footer-fixed {
+ left: 0;
+ right: 0;
+ width: 100%;
+ position: fixed;
+ z-index: 1000;
+}
+.ui-page-pre-in {
+ opacity: 0;
+}
+.ui-header-fixed {
+ top: 0;
+}
+.ui-footer-fixed {
+ bottom: 0;
+}
+.ui-header-fullscreen,
+.ui-footer-fullscreen {
+ opacity: .9;
+}
+.ui-page-header-fixed {
+ padding-top: 2.6875em;
+}
+.ui-page-footer-fixed {
+ padding-bottom: 2.6875em;
+}
+.ui-page-header-fullscreen .ui-content,
+.ui-page-footer-fullscreen .ui-content {
+ padding: 0;
+}
+.ui-fixed-hidden {
+ position: absolute;
+}
+.ui-page-header-fullscreen .ui-fixed-hidden,
+.ui-page-footer-fullscreen .ui-fixed-hidden {
+ left: -99999em;
+}
+.ui-header-fixed .ui-btn,
+.ui-footer-fixed .ui-btn {
+ z-index: 10;
+}
+.ui-navbar { max-width: 100%; }
+.ui-navbar ul { list-style:none; margin: 0; padding: 0; position: relative; display: block; border: 0; max-width: 100%; overflow:hidden; }
+.ui-navbar li .ui-btn { display: block; text-align: center; margin: 0 -1px 0 0; border-right-width: 0; }
+.ui-navbar li .ui-btn-icon-right .ui-icon { right: 6px; }
+/* add border if not in header/footer (full width) */
+.ui-navbar li:last-child .ui-btn,
+.ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: 0; border-right-width: 1px; }
+.ui-header .ui-navbar li:last-child .ui-btn,
+.ui-footer .ui-navbar li:last-child .ui-btn,
+.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,
+.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: -1px; border-right-width: 0; }
+.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn { margin-right: -1px; border-right-width: 1px; }
+.ui-header .ui-navbar li .ui-btn,
+.ui-footer .ui-navbar li .ui-btn { border-top-width: 0; border-bottom-width: 0; }
+/* fixing gaps caused by subpixel problem */
+.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,
+.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn { margin-right: -5px; }
+.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
+.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
+.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,
+.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn { margin-right: -4px; }
+.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
+.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
+.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
+.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
+.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,
+.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon { right: 8px; }
+.ui-navbar li .ui-btn .ui-btn-inner { padding-top: .7em; padding-bottom: .8em }
+.ui-navbar li .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
+.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
+.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 0; padding: 0; }
+.ui-btn.ui-mini { margin-top: .25em; margin-bottom: .25em; }
+.ui-btn-left, .ui-btn-right, .ui-input-clear, .ui-btn-inline,
+.ui-grid-a .ui-btn, .ui-grid-b .ui-btn, .ui-grid-c .ui-btn, .ui-grid-d .ui-btn, .ui-grid-e .ui-btn, .ui-grid-solo .ui-btn { margin-right: 5px; }
+.ui-btn-inner { font-size: 16px; padding: .6em 20px; min-width: .75em; display: block; position: relative; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; zoom: 1; }
+.ui-btn input, .ui-btn button { z-index: 2; }
+.ui-btn-left, .ui-btn-right, .ui-btn-inline { display: inline-block; vertical-align: middle; width:99%}
+.ui-btn-block { display: block; }
+.ui-header .ui-btn,
+.ui-footer .ui-btn { display: inline-block; margin: 0; }
+.ui-header .ui-btn-block,
+.ui-footer .ui-btn-block { display: block; }
+.ui-header .ui-btn-inner,
+.ui-footer .ui-btn-inner,
+.ui-mini .ui-btn-inner { font-size: 12.5px; padding: .55em 11px .5em; }
+.ui-header .ui-fullsize .ui-btn-inner,
+.ui-footer .ui-fullsize .ui-btn-inner { font-size: 16px; padding: .6em 25px; }
+.ui-btn-icon-notext { width: 24px; height: 24px; }
+.ui-btn-icon-notext .ui-btn-inner { padding: 0; height: 100%; }
+.ui-btn-icon-notext .ui-btn-inner .ui-icon { margin: 2px 1px 2px 3px; float: left; }
+.ui-btn-text { position: relative; z-index: 1; width: 100%; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; }
+.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -9999px; }
+.ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
+.ui-btn-icon-right .ui-btn-inner { padding-right: 40px; }
+.ui-btn-icon-top .ui-btn-inner { padding-top: 40px; }
+.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 40px; }
+.ui-header .ui-btn-icon-left .ui-btn-inner,
+.ui-footer .ui-btn-icon-left .ui-btn-inner,
+.ui-mini.ui-btn-icon-left .ui-btn-inner,
+.ui-mini .ui-btn-icon-left .ui-btn-inner { padding-left: 30px; }
+.ui-header .ui-btn-icon-right .ui-btn-inner,
+.ui-footer .ui-btn-icon-right .ui-btn-inner,
+.ui-mini.ui-btn-icon-right .ui-btn-inner,
+.ui-mini .ui-btn-icon-right .ui-btn-inner { padding-right: 30px; }
+.ui-header .ui-btn-icon-top .ui-btn-inner,
+.ui-footer .ui-btn-icon-top .ui-btn-inner { padding: 30px 3px .5em 3px; }
+.ui-mini.ui-btn-icon-top .ui-btn-inner,
+.ui-mini .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
+.ui-header .ui-btn-icon-bottom .ui-btn-inner,
+.ui-footer .ui-btn-icon-bottom .ui-btn-inner { padding: .55em 3px 30px 3px; }
+.ui-mini.ui-btn-icon-bottom .ui-btn-inner,
+.ui-mini .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
+/*btn icon positioning*/
+.ui-btn-icon-notext .ui-icon { display: block; z-index: 0;}
+.ui-btn-icon-left > .ui-btn-inner > .ui-icon, .ui-btn-icon-right > .ui-btn-inner > .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
+.ui-btn-icon-top .ui-btn-inner .ui-icon, .ui-btn-icon-bottom .ui-btn-inner .ui-icon { position: absolute; left: 50%; margin-left: -9px; }
+.ui-btn-icon-left .ui-icon { left: 10px; }
+.ui-btn-icon-right .ui-icon { right: 10px; }
+.ui-btn-icon-top .ui-icon { top: 10px; }
+.ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
+.ui-header .ui-btn-icon-left .ui-icon,
+.ui-footer .ui-btn-icon-left .ui-icon,
+.ui-mini.ui-btn-icon-left .ui-icon,
+.ui-mini .ui-btn-icon-left .ui-icon { left: 5px; }
+.ui-header .ui-btn-icon-right .ui-icon,
+.ui-footer .ui-btn-icon-right .ui-icon,
+.ui-mini.ui-btn-icon-right .ui-icon,
+.ui-mini .ui-btn-icon-right .ui-icon { right: 5px; }
+.ui-header .ui-btn-icon-top .ui-icon,
+.ui-footer .ui-btn-icon-top .ui-icon,
+.ui-mini.ui-btn-icon-top .ui-icon,
+.ui-mini .ui-btn-icon-top .ui-icon { top: 5px; }
+.ui-header .ui-btn-icon-bottom .ui-icon,
+.ui-footer .ui-btn-icon-bottom .ui-icon,
+.ui-mini.ui-btn-icon-bottom .ui-icon,
+.ui-mini .ui-btn-icon-bottom .ui-icon { bottom: 5px; }
+/*hiding native button,inputs */
+.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: none; opacity: .1; cursor: pointer; background: #fff; background: rgba(255,255,255,0); filter: Alpha(Opacity=0); font-size: 1px; border: none; text-indent: -9999px; }
+.ui-field-contain .ui-btn.ui-submit { margin: 0; }
+label.ui-submit { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
+@media all and (min-width: 450px){
+ .ui-field-contain label.ui-submit { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-field-contain .ui-btn.ui-submit { width: 60%; display: inline-block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
+ .ui-hide-label .ui-btn.ui-submit { width: auto; }
+}
+.ui-collapsible { margin: .5em 0; }
+.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -8px; padding: 0; border-width: 0 0 1px 0; position: relative; }
+.ui-collapsible-heading .ui-btn { text-align: left; margin: 0; }
+.ui-collapsible-heading .ui-btn-inner,
+.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
+.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner { padding-left: 12px; padding-right: 40px; }
+.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,
+.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner { padding-right: 40px; text-align: center; }
+.ui-collapsible-heading .ui-btn span.ui-btn { position: absolute; left: 6px; top: 50%; margin: -12px 0 0 0; width: 20px; height: 20px; padding: 1px 0px 1px 2px; text-indent: -9999px; }
+.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner { padding: 10px 0; }
+.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon { left: 0; margin-top: -10px; }
+.ui-collapsible-heading-status { position: absolute; top: -9999px; left:0px; }
+.ui-collapsible-content {
+ display: block;
+ margin: 0 -8px;
+ padding: 10px 16px;
+ border-top: none; /* Overrides ui-btn-up-* */
+ background-image: none; /* Overrides ui-btn-up-* */
+ font-weight: normal; /* Overrides ui-btn-up-* */
+}
+.ui-collapsible-content-collapsed { display: none; }
+.ui-collapsible-set { margin: .5em 0; }
+.ui-collapsible-set .ui-collapsible { margin: -1px 0 0; }
+.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0; zoom: 1; }
+.ui-controlgroup.ui-mini, fieldset.ui-controlgroup.ui-mini { margin: .25em 0; }
+.ui-field-contain .ui-controlgroup, .ui-field-contain fieldset.ui-controlgroup { margin: 0; }
+.ui-bar .ui-controlgroup { margin: 0 5px; }
+.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .4em; }
+.ui-controlgroup-controls { display: block; width: 100%;}
+.ui-controlgroup li { list-style: none; }
+.ui-controlgroup-vertical .ui-btn,
+.ui-controlgroup-vertical .ui-checkbox, .ui-controlgroup-vertical .ui-radio { margin: 0; border-bottom-width: 0; }
+.ui-controlgroup-vertical .ui-controlgroup-last { border-bottom-width: 1px; }
+.ui-controlgroup-controls label.ui-select { position: absolute; left: -9999px; }
+.ui-controlgroup .ui-btn-icon-notext { width: 24px; height: 24px; }
+.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; right: 50%; margin: -9px -9px 0 0; }
+.ui-controlgroup-horizontal .ui-controlgroup-controls:before,
+.ui-controlgroup-horizontal .ui-controlgroup-controls:after { content: ""; display: table; }
+.ui-controlgroup-horizontal .ui-controlgroup-controls:after { clear: both; }
+.ui-controlgroup-horizontal .ui-controlgroup-controls { zoom: 1; }
+.ui-controlgroup-horizontal .ui-btn-inner { text-align: center; }
+.ui-controlgroup-horizontal .ui-btn, .ui-controlgroup-horizontal .ui-select,
+.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio { float: left; clear: none; margin: 0 -1px 0 0; }
+.ui-controlgroup-horizontal .ui-select .ui-btn,
+.ui-controlgroup-horizontal .ui-checkbox .ui-btn, .ui-controlgroup-horizontal .ui-radio .ui-btn,
+.ui-controlgroup-horizontal .ui-checkbox:last-child, .ui-controlgroup-horizontal .ui-radio:last-child { margin-right: 0; }
+.ui-controlgroup-horizontal .ui-controlgroup-last { margin-right: 0; }
+.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }
+@media all and (min-width: 450px){
+ .ui-field-contain .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-field-contain .ui-controlgroup-controls { width: 60%; display: inline-block; }
+ .ui-field-contain .ui-controlgroup .ui-select { width: 100%; display: block; }
+ .ui-field-contain .ui-controlgroup-horizontal .ui-select { width: auto; }
+ .ui-hide-label .ui-controlgroup-controls { width: 100%; }
+}
+.ui-dialog {
+ background: none !important; /* this is to ensure that dialog theming does not apply (by default at least) on the page div */
+}
+.ui-dialog-contain { width: 92.5%; max-width: 500px; margin: 10% auto 15px auto; padding: 0; }
+.ui-dialog .ui-header {
+ margin-top: 15%;
+ border: none;
+ overflow: hidden;
+}
+.ui-dialog .ui-header,
+.ui-dialog .ui-content,
+.ui-dialog .ui-footer {
+ display: block;
+ position: relative;
+ width: auto;
+}
+.ui-dialog .ui-header,
+.ui-dialog .ui-footer {
+ z-index: 10;
+ padding: 0;
+}
+.ui-dialog .ui-footer {
+ padding: 0 15px;
+}
+.ui-dialog .ui-content {
+ padding: 15px;
+}
+.ui-dialog {
+ margin-top: -15px;
+}
+.ui-checkbox, .ui-radio { position: relative; clear: both; margin: 0; z-index: 1; }
+.ui-checkbox .ui-btn, .ui-radio .ui-btn { margin: .5em 0; text-align: left; z-index: 2; }
+.ui-checkbox .ui-btn.ui-mini, .ui-radio .ui-btn.ui-mini { margin: .25em 0; }
+.ui-controlgroup .ui-checkbox .ui-btn, .ui-controlgroup .ui-radio .ui-btn { margin: 0; }
+.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }
+.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }
+.ui-checkbox .ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-left .ui-btn-inner { padding-left: 36px; }
+.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
+.ui-checkbox .ui-mini.ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-mini.ui-btn-icon-right .ui-btn-inner { padding-right: 36px; }
+.ui-checkbox .ui-btn-icon-top .ui-btn-inner,.ui-radio .ui-btn-icon-top .ui-btn-inner { padding-right: 0; padding-left: 0; text-align: center; }
+.ui-checkbox .ui-btn-icon-bottom .ui-btn-inner, .ui-radio .ui-btn-icon-bottom .ui-btn-inner { padding-right: 0; padding-left: 0; text-align: center; }
+.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }
+.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon { left: 15px; }
+.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon, .ui-radio .ui-mini.ui-btn-icon-left .ui-icon { left: 9px; }
+.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
+.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
+.ui-checkbox .ui-btn-icon-top .ui-icon, .ui-radio .ui-btn-icon-top .ui-icon { top: 10px; }
+.ui-checkbox .ui-btn-icon-bottom .ui-icon, .ui-radio .ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
+.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
+.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
+/* input, label positioning */
+.ui-checkbox input,.ui-radio input { position:absolute; left:20px; top:50%; width: 10px; height: 10px; margin:-5px 0 0 0; outline: 0 !important; z-index: 1; }
+.ui-field-contain, fieldset.ui-field-contain { padding: .8em 0; margin: 0; border-width: 0 0 1px 0; overflow: visible; }
+.ui-field-contain:last-child { border-bottom-width: 0; }
+.ui-field-contain { max-width: 100%; } /* This prevents horizontal scrollbar in IE7 */
+@media all and (min-width: 450px){
+ .ui-field-contain, .ui-mobile fieldset.ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
+}
+.ui-select { display: block; position: relative; }
+.ui-select select { position: absolute; left: -9999px; top: -9999px; }
+.ui-select .ui-btn { overflow: hidden; opacity: 1; }
+.ui-field-contain .ui-select .ui-btn { margin: 0; }
+/* Fixes #2588 — When Windows Phone 7.5 (Mango) tries to calculate a numeric opacity for a select—including “inherit”—without explicitly specifying an opacity on the parent to give it context, a bug appears where clicking elsewhere on the page after opening the select will open the select again. */
+.ui-select .ui-btn select { cursor: pointer; -webkit-appearance: none; left: 0; top:0; width: 100%; min-height: 1.5em; min-height: 100%; height: 3em; max-height: 100%; opacity: 0; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter: alpha(opacity=0); z-index: 2; }
+.ui-select .ui-disabled { opacity: .3; }
+@-moz-document url-prefix() {.ui-select .ui-btn select { opacity: 0.0001; }}
+.ui-select .ui-btn.ui-select-nativeonly { border-radius: 0; }
+.ui-select .ui-btn.ui-select-nativeonly select { opacity: 1; text-indent: 0; }
+.ui-select .ui-btn-icon-right .ui-btn-inner, .ui-select .ui-li-has-count .ui-btn-inner { padding-right: 45px; }
+.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner { padding-right: 32px; }
+.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 80px; }
+.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 67px; }
+.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
+.ui-select .ui-mini.ui-btn-icon-right .ui-icon { right: 7px; }
+.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 45px; }
+.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 32px; }
+/* labels */
+label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
+/*listbox*/
+.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: block; min-height: 1em; overflow: hidden !important;
+/* This !important is required for iPad Safari specifically. See https://github.com/jquery/jquery-mobile/issues/2647 */ }
+.ui-select .ui-btn-text { text-overflow: ellipsis; }
+.ui-selectmenu { position: absolute; padding: 0; z-index: 1100 !important; width: 80%; max-width: 350px; padding: 6px; }
+.ui-selectmenu .ui-listview { margin: 0; }
+.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }
+.ui-selectmenu-hidden { top: -99999px; left: -9999px; }
+.ui-selectmenu-screen { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 99; }
+.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }
+.ui-selectmenu-list .ui-li .ui-icon { display: block; }
+.ui-li.ui-selectmenu-placeholder { display: none; }
+.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }
+@media all and (min-width: 450px){
+ .ui-field-contain label.ui-select { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-field-contain .ui-select { width: 60%; display: inline-block; }
+ .ui-hide-label .ui-select { width: 100%; }
+}
+/* when no placeholder is defined in a multiple select, the header height doesn't even extend past the close button. this shim's content in there */
+.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }
+label.ui-input-text { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; padding-right: 1em;}
+input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; margin: .5em 0; line-height: 1.4; font-size: 16px; width: 100%; outline: 0; }
+input.ui-input-text.ui-mini, textarea.ui-input-text.ui-mini { margin: .25em 0; }
+.ui-field-contain input.ui-input-text, .ui-field-contain textarea.ui-input-text { margin: 0; }
+input.ui-input-text, textarea.ui-input-text, .ui-input-search { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
+input.ui-input-text { -webkit-appearance: none; }
+textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }
+.ui-input-search { padding: 0 30px; margin: .5em 0; background-image: none; position: relative; }
+.ui-input-search.ui-mini { margin: .25em 0; }
+.ui-field-contain .ui-input-search { margin: 0; }
+.ui-icon-searchfield:after { position: absolute; left: 7px; top: 50%; margin-top: -9px; content: ""; width: 18px; height: 18px; opacity: .5; }
+.ui-input-search input.ui-input-text { border: none; width: 98%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }
+.ui-input-search .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -13px; }
+.ui-mini .ui-input-clear { right: -3px; }
+.ui-input-search .ui-input-clear-hidden { display: none; }
+input.ui-mini, .ui-mini input, textarea.ui-mini { font-size: 14px; }
+textarea.ui-mini { height: 45px; }
+@media all and (min-width: 450px){
+ .ui-field-contain label.ui-input-text { vertical-align: top; width: 100%; margin: 0 2% 0 0 }
+ .ui-field-contain input.ui-input-text,
+ .ui-field-contain textarea.ui-input-text,
+ .ui-field-contain .ui-input-search { width: 100%; display: inline-block; }
+ .ui-hide-label input.ui-input-text,
+ .ui-hide-label textarea.ui-input-text,
+ .ui-hide-label .ui-input-search { width: 100%; }
+ .ui-input-search input.ui-input-text { width: 98%; /*echos rule from above*/ }
+}
+.ui-listview { margin: 0; counter-reset: listnumbering; }
+.ui-content .ui-listview { margin: -15px; }
+.ui-content .ui-listview-inset { margin: 1em 0; }
+.ui-listview, .ui-li { list-style:none; padding:0; }
+.ui-li, .ui-li.ui-field-contain { display: block; margin:0; position: relative; overflow: visible; text-align: left; border-width: 0; border-top-width: 1px; }
+.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-divider, .ui-li-static { padding: .5em 15px; font-size: 14px; font-weight: bold; }
+/* Fixes #4254 to prevent inherit font-size from .ui-li-divider, .ui-li-static */
+.ui-li-divider .ui-btn-text, .ui-li-static .ui-btn-text { font-size: 16px; }
+.ui-li-divider .ui-mini .ui-btn-text, .ui-li-static .ui-mini .ui-btn-text { font-size: inherit; }
+.ui-li-divider { counter-reset: listnumbering; }
+ol.ui-listview .ui-link-inherit:before, ol.ui-listview .ui-li-static:before, .ui-li-dec { font-size: .8em; display: inline-block; padding-right: .3em; font-weight: normal;counter-increment: listnumbering; content: counter(listnumbering) ". "; }
+ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */
+.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }
+.ui-li:last-child, .ui-li.ui-field-contain:last-child { border-bottom-width: 1px; }
+.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }
+.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 15px; display: block; }
+.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 60px; padding-left: 100px; }
+.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }
+.ui-li-has-count .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-count, .ui-li-divider.ui-li-has-count { padding-right: 45px; }
+.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow { padding-right: 40px; }
+.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow.ui-li-has-count { padding-right: 75px; }
+.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
+.ui-li-thumb, .ui-listview .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }
+.ui-listview .ui-li-icon { max-height: 16px; max-width: 16px; left: 10px; top: .9em; }
+.ui-li-thumb, .ui-listview .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }
+.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
+@media all and (min-width: 480px){
+ .ui-li-aside { width: 45%; }
+}
+.ui-li-divider { cursor: default; }
+.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 53px; }
+.ui-li-has-alt.ui-li-has-count .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt.ui-li-has-count { padding-right: 88px; }
+.ui-li-has-count .ui-li-count { position: absolute; font-size: 11px; font-weight: bold; padding: .2em .5em; top: 50%; margin-top: -.9em; right: 10px; }
+.ui-li-has-count.ui-li-divider .ui-li-count, .ui-li-has-count .ui-link-inherit .ui-li-count { margin-top: -.95em; }
+.ui-li-has-arrow.ui-li-has-count .ui-li-count { right: 40px; }
+.ui-li-has-alt.ui-li-has-count .ui-li-count { right: 53px; }
+.ui-li-link-alt { position: absolute; width: 40px; height: 100%; border-width: 0; border-left-width: 1px; top: 0; right: 0; margin: 0; padding: 0; z-index: 2; }
+.ui-li-link-alt .ui-btn { overflow: hidden; position: absolute; right: 8px; top: 50%; margin: -13px 0 0 0; border-bottom-width: 1px; z-index: -1;}
+.ui-li-link-alt .ui-btn-inner { padding: 0; height: 100%; position: absolute; width: 100%; top: 0; left: 0;}
+.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }
+.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
+.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner { border-top: 0px; }
+.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px }
+.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }
+.ui-listview-filter-inset { margin: -15px -5px -15px -5px; background: transparent; }
+.ui-li.ui-screen-hidden{display:none;}
+/* Odd iPad positioning issue. */
+@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
+ .ui-li .ui-btn-text { overflow: visible; }
+}
+label.ui-slider { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
+input.ui-slider-input,
+.ui-field-contain input.ui-slider-input { display: inline-block; width: 50px; background-image: none; padding: .4em; margin: .5em 0; line-height: 1.4; font-size: 16px; outline: 0; }
+input.ui-slider-input.ui-mini,
+.ui-field-contain input.ui-slider-input.ui-mini { width: 45px; margin: .25em 0; font-size: 14px; }
+.ui-field-contain input.ui-slider-input { margin: 0; }
+/* To do: Exclude ui-slider-input from textinput widget initSelector. The class ui-input-text is added to the slider input and label. When this is fixed, the rule below can be deleted. */
+input.ui-slider-input, .ui-field-contain input.ui-slider-input { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; -ms-box-sizing: content-box; box-sizing: content-box; }
+select.ui-slider-switch { display: none; }
+div.ui-slider { position: relative; display: inline-block; overflow: visible; height: 15px; padding: 0; margin: 0 2% 0 20px; top: 4px; width: 65%; }
+div.ui-slider-mini { height: 12px; margin-left: 10px; top: 2px; }
+div.ui-slider-bg { border: none; height: 100%; padding-right: 8px; }
+.ui-controlgroup a.ui-slider-handle, a.ui-slider-handle { position: absolute; z-index: 1; top: 50%; width: 28px; height: 28px; margin-top: -15px; margin-left: -15px; outline: 0; }
+a.ui-slider-handle .ui-btn-inner { padding: 0; height: 100%; }
+div.ui-slider-mini a.ui-slider-handle { height: 14px; width: 14px; margin: -8px 0 0 -7px; }
+div.ui-slider-mini a.ui-slider-handle .ui-btn-inner { height: 30px; width: 30px; padding: 0; margin: -9px 0 0 -9px; border-top: none; }
+@media all and (min-width: 450px){
+ .ui-field-contain label.ui-slider { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
+ .ui-field-contain div.ui-slider { width: 43%; }
+ .ui-field-contain div.ui-slider-switch { width: 5.5em; }
+}
+div.ui-slider-switch { height: 32px; margin-left: 0; width: 5.0em; }
+a.ui-slider-handle-snapping { -webkit-transition: left 70ms linear; -moz-transition: left 70ms linear; }
+div.ui-slider-switch .ui-slider-handle { margin-top: 1px; }
+.ui-slider-inneroffset { margin: 0 16px; position: relative; z-index: 1; }
+div.ui-slider-switch.ui-slider-mini { width: 5em; height: 29px; }
+div.ui-slider-switch.ui-slider-mini .ui-slider-inneroffset { margin: 0 15px 0 14px; }
+div.ui-slider-switch.ui-slider-mini .ui-slider-handle { width: 25px; height: 25px; margin: 1px 0 0 -13px; }
+div.ui-slider-switch.ui-slider-mini a.ui-slider-handle .ui-btn-inner { height: 30px; width: 30px; padding: 0; margin: 0; }
+span.ui-slider-label { position: absolute; text-align: center; width: 100%; overflow: hidden; font-size: 16px; top: 0; line-height: 2; min-height: 100%; border-width: 0; white-space: nowrap; }
+.ui-slider-mini span.ui-slider-label { font-size: 14px; }
+span.ui-slider-label-a { z-index: 1; left: 0; text-indent: -1.5em; }
+span.ui-slider-label-b { z-index: 0; right: 0; text-indent: 1.5em;}
+.ui-slider-inline { width: 120px; display: inline-block; }
--- /dev/null
+/* Datewheel overlay */\r
+.dw {\r
+ min-width:170px;\r
+ padding: 0 10px;\r
+ position: absolute;\r
+ top: 5%;\r
+ left: 0;\r
+ z-index: 1001;\r
+ color: #000;\r
+ font-family: arial, verdana, sans-serif;\r
+ font-size: 12px;\r
+ text-shadow: none;\r
+}\r
+.dwi {\r
+ position: static;\r
+ margin: 5px;\r
+ display: inline-block;\r
+}\r
+.dwwr {\r
+ zoom: 1;\r
+}\r
+/* Datewheel overlay background */\r
+.dwo {\r
+ width: 100%;\r
+ background: #000;\r
+ position: absolute;\r
+ top: 0;\r
+ left: 0;\r
+ z-index: 1000;\r
+ opacity: .7;\r
+ filter:Alpha(Opacity=70);\r
+}\r
+/* Datewheel wheel container wrapper */\r
+.dwc {\r
+ float: left;\r
+ margin: 0 2px 5px 2px;\r
+ padding-top: 30px;\r
+}\r
+.dwcc {\r
+ clear: both;\r
+}\r
+/* Datewheel label */\r
+.dwl {\r
+ /*margin: 0 2px;*/\r
+ text-align: center;\r
+ line-height: 30px;\r
+ height: 30px;\r
+ white-space: nowrap;\r
+ position: absolute;\r
+ top: -30px;\r
+ width: 100%;\r
+}\r
+/* Datewheel value */\r
+.dwv {\r
+ padding: 10px 0;\r
+ border-bottom: 1px solid #000;\r
+}\r
+/* Datewheel wheel container */\r
+.dwrc {\r
+ -webkit-border-radius: 3px;\r
+ -moz-border-radius: 3px;\r
+ border-radius: 3px;\r
+}\r
+.dwwc {\r
+ margin: 0;\r
+ padding: 0 2px;\r
+ position: relative;\r
+ background: #000;\r
+ zoom:1;\r
+}\r
+/* Datewheel wheels */\r
+.dwwl {\r
+ margin: 4px 2px;\r
+ position: relative;\r
+ background: #888;\r
+ background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #000),color-stop(0.35, #333),color-stop(0.50, #888),color-stop(0.65, #333),color-stop(1, #000));\r
+ background: -moz-linear-gradient(#000 0%,#333 35%, #888 50%,#333 65%,#000 100%);\r
+ background: -ms-linear-gradient(#000 0%,#333 35%, #888 50%,#333 65%,#000 100%);\r
+ background: -o-linear-gradient(#000 0%,#333 35%, #888 50%,#333 65%,#000 100%);\r
+}\r
+.dww {\r
+ margin: 0 2px;\r
+ overflow: hidden;\r
+ position: relative;\r
+ /*top: -30px;*/\r
+}\r
+.dwsc .dww {\r
+ color: #fff;\r
+ background: #444;\r
+ background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #000),color-stop(0.45, #444),color-stop(0.55, #444),color-stop(1, #000));\r
+ background: -moz-linear-gradient(#000 0%,#444 45%, #444 55%, #000 100%);\r
+ background: -ms-linear-gradient(#000 0%,#444 45%, #444 55%, #000 100%);\r
+ background: -o-linear-gradient(#000 0%,#444 45%, #444 55%, #000 100%);\r
+}\r
+.dww ul {\r
+ list-style: none;\r
+ margin: 0;\r
+ padding: 0;\r
+ /*display: block;\r
+ width: 100%;*/\r
+ position: relative;\r
+ z-index: 2;\r
+}\r
+.dww li {\r
+ list-style: none;\r
+ margin: 0;\r
+ padding: 0 5px;\r
+ display: block;\r
+ text-align: center;\r
+ line-height: 40px;\r
+ font-size: 26px;\r
+ white-space: nowrap;\r
+ text-shadow: 0 1px 1px #000;\r
+ opacity: .3;\r
+ filter: Alpha(Opacity=30);\r
+}\r
+/* Valid entry */\r
+.dww li.dw-v {\r
+ opacity: 1;\r
+ filter: Alpha(Opacity=100);\r
+}\r
+/* Hidden entry */\r
+.dww li.dw-h {\r
+ visibility: hidden;\r
+}\r
+/* Wheel +/- buttons */\r
+.dwwb {\r
+ position: absolute;\r
+ z-index: 4;\r
+ left: 0;\r
+ cursor: pointer;\r
+ width: 100%;\r
+ height: 40px;\r
+ text-align: center;\r
+}\r
+.dwwbp {\r
+ top: 0;\r
+ -webkit-border-radius: 3px 3px 0 0;\r
+ -moz-border-radius: 3px 3px 0 0;\r
+ border-radius: 3px 3px 0 0;\r
+ font-size: 40px;\r
+}\r
+.dwwbm {\r
+ bottom: 0;\r
+ -webkit-border-radius: 0 0 3px 3px;\r
+ -moz-border-radius: 0 0 3px 3px;\r
+ border-radius: 0 0 3px 3px;\r
+ font-size: 32px;\r
+ font-weight: bold;\r
+}\r
+.dwpm .dwwc {\r
+ background: transparent;\r
+}\r
+.dwpm .dww {\r
+ margin: -1px;\r
+}\r
+.dwpm .dww li {\r
+ text-shadow: none;\r
+}\r
+.dwpm .dwwol {\r
+ display: none;\r
+}\r
+/* Datewheel wheel overlay */\r
+.dwwo {\r
+ position: absolute;\r
+ z-index: 3;\r
+ top: 0;\r
+ left: 0;\r
+ width: 100%;\r
+ height: 100%;\r
+ background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #000),color-stop(0.52, rgba(44,44,44,0)),color-stop(0.48, rgba(44,44,44,0)),color-stop(1, #000));\r
+ background: -moz-linear-gradient(#000 0%,rgba(44,44,44,0) 52%, rgba(44,44,44,0) 48%, #000 100%);\r
+ background: -ms-linear-gradient(#000 0%,rgba(44,44,44,0) 52%, rgba(44,44,44,0) 48%, #000 100%);\r
+ background: -o-linear-gradient(#000 0%,rgba(44,44,44,0) 52%, rgba(44,44,44,0) 48%, #000 100%);\r
+}\r
+/* Background line */\r
+.dwwol {\r
+ position: absolute;\r
+ z-index: 1;\r
+ top: 50%;\r
+ left: 0;\r
+ width: 100%;\r
+ height: 0;\r
+ margin-top: -1px;\r
+ border-top: 1px solid #333;\r
+ border-bottom: 1px solid #555;\r
+}\r
+/* Datewheel button */\r
+.dwbg .dwb {\r
+ display: block;\r
+ height: 40px;\r
+ line-height: 40px;\r
+ padding: 0 15px;\r
+ margin: 0 2px;\r
+ font-size: 14px;\r
+ font-weight: bold;\r
+ text-decoration: none;\r
+ text-shadow:0 -1px 1px #000;\r
+ border-radius: 5px;\r
+ -moz-border-radius: 5px;\r
+ -webkit-border-radius:5px;\r
+ box-shadow:0 1px 3px rgba(0,0,0,0.5);\r
+ -moz-box-shadow:0 1px 3px rgba(0,0,0,0.5);\r
+ -webkit-box-shadow:0 1px 3px rgba(0,0,0,0.5);\r
+ color: #fff;\r
+ background:#000;\r
+ background:-webkit-gradient(linear,left bottom,left top,color-stop(0.5, #000),color-stop(0.5, #6e6e6e));\r
+ background:-moz-linear-gradient(#6e6e6e 50%,#000 50%);\r
+ background:-ms-linear-gradient(#6e6e6e 50%,#000 50%);\r
+ background:-o-linear-gradient(#6e6e6e 50%,#000 50%);\r
+}\r
+/* Datewheel button container */\r
+.dwbc {\r
+ /*margin-top: 5px;*/\r
+ padding: 5px 0;\r
+ text-align: center;\r
+ clear: both;\r
+}\r
+/* Datewheel button wrapper */\r
+.dwbw {\r
+ display: inline-block;\r
+ width: 50%;\r
+}\r
+/* Hidden label */\r
+.dwhl {\r
+ padding-top: 10px;\r
+}\r
+.dwhl .dwl {\r
+ display: none;\r
+}\r
+/* Backgrounds */\r
+.dwbg {\r
+ background: #fff;\r
+ border-radius: 3px;\r
+ -webkit-border-radius: 3px;\r
+ -moz-border-radius: 3px;\r
+}\r
+.dwbg .dwpm .dww {\r
+ color: #000;\r
+ background: #fff;\r
+ border: 1px solid #AAA;\r
+}\r
+.dwbg .dwwb {\r
+ background: #ccc;\r
+ color: #888;\r
+ text-shadow: 0 -1px 1px #333;\r
+ box-shadow: 0 0 5px #333;\r
+ -webkit-box-shadow: 0 0 5px #333;\r
+ -moz-box-shadow: 0 0 5px #333;\r
+}\r
+.dwbg .dwwbp {\r
+ background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #bdbdbd),color-stop(1, #f7f7f7));\r
+ background: -moz-linear-gradient(#f7f7f7,#bdbdbd);\r
+ background: -ms-linear-gradient(#f7f7f7,#bdbdbd);\r
+ background: -o-linear-gradient(#f7f7f7,#bdbdbd);\r
+}\r
+.dwbg .dwwbm {\r
+ background: -webkit-gradient(linear,left bottom,left top,color-stop(0, #f7f7f7),color-stop(1, #bdbdbd));\r
+ background: -moz-linear-gradient(#bdbdbd,#f7f7f7);\r
+ background: -ms-linear-gradient(#bdbdbd,#f7f7f7);\r
+ background: -o-linear-gradient(#bdbdbd,#f7f7f7);\r
+}\r
+.dwbg .dwb-a {\r
+ background:#3c7500;\r
+ background:-webkit-gradient(linear,left bottom,left top,color-stop(0.5, #3c7500),color-stop(0.5, #94c840));\r
+ background:-moz-linear-gradient(#94c840 50%,#3c7500 50%);\r
+ background:-ms-linear-gradient(#94c840 50%,#3c7500 50%);\r
+ background:-o-linear-gradient(#94c840 50%,#3c7500 50%);\r
+}\r
+.dwbg .dwwl .dwb-a {\r
+ background:#3c7500;\r
+ background:-webkit-gradient(linear,left bottom,left top,color-stop(0, #3c7500),color-stop(1, #94c840));\r
+ background:-moz-linear-gradient(#94c840,#3c7500);\r
+ background:-ms-linear-gradient(#94c840,#3c7500);\r
+ background:-o-linear-gradient(#94c840,#3c7500);\r
+}\r
--- /dev/null
+/* jQuery Mobile Theme */\r
+.jqm .dwo {\r
+ background: none;\r
+}\r
+.jqm .dw {\r
+ padding: 6px;\r
+ z-index: 1003;\r
+}\r
+.jqm .dwv {\r
+ position: static;\r
+ width: auto;\r
+ padding: .7em 15px .7em 15px;\r
+ border: 0;\r
+}\r
+.jqm .dwwr {\r
+ border: 0;\r
+}\r
+.jqm .dwpm .dwwo {\r
+ background: none;\r
+}\r
+.jqm .dwc {\r
+ margin: 0;\r
+ padding: 30px 5px 5px 5px;\r
+ }\r
+.jqm .dwhl {\r
+ padding: 5px;\r
+}\r
+.jqm .dwwb {\r
+ margin: 0;\r
+ border: 0;\r
+}\r
+.jqm .dwwb span {\r
+ padding: 0;\r
+}\r
+.jqm .dwwbp .ui-btn-inner {\r
+ -webkit-border-radius: 3px 3px 0 0;\r
+ -moz-border-radius: 3px 3px 0 0;\r
+ border-radius: 3px 3px 0 0;\r
+}\r
+.jqm .dwwbm .ui-btn-inner {\r
+ -webkit-border-radius: 0 0 3px 3px;\r
+ -moz-border-radius: 0 0 3px 3px;\r
+ border-radius: 0 0 3px 3px;\r
+}\r
+.jqm .dwwbp span {\r
+ font-weight: normal;\r
+}\r
--- /dev/null
+<!DOCTYPE html>
+<html>
+
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>JPush Phonegap Simple Demo</title>
+ <link href="css/jquery.mobile-1.1.1.css" rel="stylesheet" type="text/css" />
+ <script type="text/javascript" src="js/jquery.js"></script>
+ <script type="text/javascript" src="js/jquery.mobile-1.1.1.js"></script>
+ <script type="text/javascript" src="cordova.js"></script>
+ <script type="text/javascript">
+
+ var onDeviceReady = function() {
+ document.addEventListener("jpush.receiveRegistrationId", function (event) {
+ alert("receiveRegistrationId" + JSON.stringify(event));
+ $("#registrationId").html(event.registrationId);
+ }, false)
+
+ initiateUI();
+ };
+
+ var getRegistrationID = function() {
+ window.JPush.getRegistrationID(onGetRegistrationID);
+ };
+
+ var onGetRegistrationID = function(data) {
+ try {
+ console.log("JPushPlugin:registrationID is " + data);
+
+ if (data.length == 0) {
+ var t1 = window.setTimeout(getRegistrationID, 1000);
+ }
+
+ $("#registrationId").html(data);
+ } catch (exception) {
+ console.log(exception);
+ }
+ };
+
+ var onTagsWithAlias = function(event) {
+ try {
+ console.log("onTagsWithAlias");
+ var result = "result code:" + event.resultCode + " ";
+ result += "tags:" + event.tags + " ";
+ result += "alias:" + event.alias + " ";
+ $("#tagAliasResult").html(result);
+ } catch (exception) {
+ console.log(exception)
+ }
+ };
+
+ var onOpenNotification = function(event) {
+ try {
+ var alertContent;
+ if (device.platform == "Android") {
+ alertContent = event.alert;
+ } else {
+ alertContent = event.aps.alert;
+ }
+ alert("open Notification:" + alertContent);
+ } catch (exception) {
+ console.log("JPushPlugin:onOpenNotification" + exception);
+ }
+ };
+
+ var onReceiveNotification = function(event) {
+ try {
+ var alertContent;
+ if (device.platform == "Android") {
+ alertContent = event.alert;
+ } else {
+ alertContent = event.aps.alert;
+ }
+ $("#notificationResult").html(alertContent);
+ } catch (exception) {
+ console.log(exception)
+ }
+ };
+
+ var onReceiveMessage = function(event) {
+ try {
+ var message;
+ if (device.platform == "Android") {
+ message = event.message;
+ } else {
+ message = event.content;
+ }
+ $("#messageResult").html(message);
+ } catch (exception) {
+ console.log("JPushPlugin:onReceiveMessage-->" + exception);
+ }
+ };
+
+ var initiateUI = function() {
+ try {
+ window.JPush.init();
+ window.JPush.setDebugMode(true);
+ window.setTimeout(getRegistrationID, 1000);
+
+ if (device.platform != "Android") {
+ window.JPush.setApplicationIconBadgeNumber(0);
+ }
+ } catch (exception) {
+ console.log(exception);
+ }
+
+ $("#setTags").click(function(ev) {
+ try {
+ var tag1 = $("#tagText1").val()
+ var tag2 = $("#tagText2").val()
+ var tag3 = $("#tagText3").val()
+ var tags = []
+
+ if (tag1) {
+ tags.push(tag1)
+ }
+ if (tag2) {
+ tags.push(tag2)
+ }
+ if (tag3) {
+ tags.push(tag3)
+ }
+
+ window.JPush.setTags({ sequence: 1, tags: tags },
+ function (result) {
+ $("#tagsResult").html(JSON.stringify(result.tags))
+ }, function (error) {
+ alert(error.code)
+ })
+ } catch (exception) {
+ console.log(exception)
+ }
+ })
+
+ $("#getAllTags").click(function (event) {
+ window.JPush.getAllTags({ sequence: 2 },
+ function (result) {
+ $("#tagsResult").html(JSON.stringify(result.tags))
+ }, function (error) {
+ alert(error.code)
+ })
+ })
+
+ $("#cleanTags").click(function (event) {
+ window.JPush.cleanTags({ sequence: 2 },
+ function (result) {
+ alert(result.sequence)
+ $("#tagsResult").html("")
+ }, function (error) {
+ alert(error.code)
+ })
+ })
+
+ $("#setAlias").click(function (event) {
+ var alias = $("#aliasText").val()
+ window.JPush.setAlias({ sequence: 1, alias: alias },
+ function (result) {
+ $("#aliasResult").html(result.alias)
+ }, function (error){
+ alert(error.code)
+ })
+ })
+
+ $("#getAlias").click(function (event) {
+ window.JPush.getAlias({ sequence: 2 },
+ function (result) {
+ alert(JSON.stringify(result));
+ }, function (error) {
+ alert(error.code)
+ })
+ });
+
+ $("#deleteAlias").click(function (event) {
+ window.JPush.deleteAlias({ sequence: 3 },
+ function (result) {
+ alert(JSON.stringify(result));
+ }, function (error) {
+ alert(error.code)
+ })
+ });
+ };
+
+ document.addEventListener("deviceready", onDeviceReady, false);
+ document.addEventListener("jpush.openNotification", onOpenNotification, false);
+ document.addEventListener("jpush.receiveNotification", onReceiveNotification, false);
+ document.addEventListener("jpush.receiveMessage", onReceiveMessage, false);
+ </script>
+ </head>
+
+ <body>
+ <div data-role="page" id="page">
+ <div data-role="content">
+ <form>
+ <div class="ui-body ui-body-b">
+ <div data-role="fieldcontain">
+ <center>
+ <h3>JPushPlugin Example</h3>
+ </center>
+ <span name="alias" id="alias"></span>
+ <hr/>
+ <label>RegistrationID: </label>
+ <label id="registrationId">null</label>
+ </div>
+ <div data-role="fieldcontain">
+ <label>Tags: </label>
+ <table>
+ <tr>
+ <td>
+ <input type="text" id="tagText1" />
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input type="text" id="tagText2" />
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <input type="text" id="tagText3" />
+ </td>
+ </tr>
+ </table>
+ <label>Alias: </label>
+ <table>
+ <tr>
+ <td>
+ <input type="text" id="aliasText" />
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <div data-role="fieldcontain">
+ <input type="button" id="setTags" value="Set tags" />
+ <input type="button" id="getAllTags" value="Get all tags" />
+ <input type="button" id="cleanTags" value="Clean tags" />
+ </div>
+
+ <div data-role="fieldcontain">
+ <input type="button" id="setAlias" value="Set alias" />
+ <input type="button" id="getAlias" value="Get alias" />
+ <input type="button" id="deleteAlias" value="Delete alias" />
+ </div>
+
+ <div data-role="fieldcontain">
+ <label id="tagsPrompt">设置 Tag 的结果:</label>
+ <label id="tagsResult">null</label>
+ </div>
+ <div data-role="fieldcontain">
+ <label id="aliasPrompt">设置 Alias 的结果:</label>
+ <label id="aliasResult">null</label>
+ </div>
+ <div data-role="fieldcontain">
+ <label id="notificationPrompt">接受的通知内容:</label>
+ <label id="notificationResult">null</label>
+ </div>
+ <div data-role="fieldcontain">
+ <label id="messagePrompt">接受的自定义消息:</label>
+ <label id="messageResult">null</label>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+/*!
+ * jQuery JavaScript Library v1.7.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: Wed Mar 21 12:46:34 2012 -0700
+ */
+(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
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ 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+$/,
+
+ // 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]|[0-9])/ig,
+ rmsPrefix = /^-ms-/,
+
+ // 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.7.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.add( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ i = +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.fireWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger( "ready" ).off( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyList ) {
+ return;
+ }
+
+ readyList = jQuery.Callbacks( "once memory" );
+
+ // 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";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( 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;
+ }
+
+ 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;
+ }
+
+ // 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 new Error( 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
+ parseXML: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+ var xml, tmp;
+ try {
+ 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 );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ 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 );
+ }
+ },
+
+ // 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.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'
+ // 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, i ) {
+ var len;
+
+ if ( array ) {
+ if ( indexOf ) {
+ return indexOf.call( array, elem, i );
+ }
+
+ len = array.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in array && 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, fn, key, value, chainable, emptyGet, pass ) {
+ var exec,
+ bulk = key == null,
+ i = 0,
+ length = elems.length;
+
+ // Sets many values
+ if ( key && typeof key === "object" ) {
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+ }
+ chainable = 1;
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = pass === undefined && jQuery.isFunction( value );
+
+ if ( bulk ) {
+ // Bulk operations only iterate when executing function values
+ if ( exec ) {
+ exec = fn;
+ fn = function( elem, key, value ) {
+ return exec.call( jQuery( elem ), value );
+ };
+
+ // Otherwise they run against the entire set
+ } else {
+ fn.call( elems, value );
+ fn = null;
+ }
+ }
+
+ if ( fn ) {
+ for (; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+ }
+
+ chainable = 1;
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ 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;
+
+})();
+
+
+// String to Object flags format cache
+var flagsCache = {};
+
+// Convert String-formatted flags into Object-formatted ones and store in cache
+function createFlags( flags ) {
+ var object = flagsCache[ flags ] = {},
+ i, length;
+ flags = flags.split( /\s+/ );
+ for ( i = 0, length = flags.length; i < length; i++ ) {
+ object[ flags[i] ] = true;
+ }
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * flags: an optional list of space-separated flags that will change how
+ * the callback list behaves
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible flags:
+ *
+ * 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( flags ) {
+
+ // Convert flags from String-formatted to Object-formatted
+ // (we check in cache first)
+ flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+
+ var // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = [],
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Add one or several callbacks to the list
+ add = function( args ) {
+ var i,
+ length,
+ elem,
+ type,
+ actual;
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ // Inspect recursively
+ add( elem );
+ } else if ( type === "function" ) {
+ // Add if not in unique mode and callback is not in
+ if ( !flags.unique || !self.has( elem ) ) {
+ list.push( elem );
+ }
+ }
+ }
+ },
+ // Fire callbacks
+ fire = function( context, args ) {
+ args = args || [];
+ memory = !flags.memory || [ context, args ];
+ fired = true;
+ firing = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
+ memory = true; // Mark as halted
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( !flags.once ) {
+ if ( stack && stack.length ) {
+ memory = stack.shift();
+ self.fireWith( memory[ 0 ], memory[ 1 ] );
+ }
+ } else if ( memory === true ) {
+ self.disable();
+ } else {
+ list = [];
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ var length = list.length;
+ add( 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, unless previous
+ // firing was halted (stopOnFalse)
+ } else if ( memory && memory !== true ) {
+ firingStart = length;
+ fire( memory[ 0 ], memory[ 1 ] );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ var args = arguments,
+ argIndex = 0,
+ argLength = args.length;
+ for ( ; argIndex < argLength ; argIndex++ ) {
+ for ( var i = 0; i < list.length; i++ ) {
+ if ( args[ argIndex ] === list[ i ] ) {
+ // Handle firingIndex and firingLength
+ if ( firing ) {
+ if ( i <= firingLength ) {
+ firingLength--;
+ if ( i <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ // Remove the element
+ list.splice( i--, 1 );
+ // If we have some unicity property then
+ // we only need to do this once
+ if ( flags.unique ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ if ( list ) {
+ var i = 0,
+ length = list.length;
+ for ( ; i < length; i++ ) {
+ if ( fn === list[ i ] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ 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 || memory === true ) {
+ 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 ( stack ) {
+ if ( firing ) {
+ if ( !flags.once ) {
+ stack.push( [ context, args ] );
+ }
+ } else if ( !( flags.once && memory ) ) {
+ fire( context, 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;
+};
+
+
+
+
+var // Static reference to slice
+ sliceDeferred = [].slice;
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var doneList = jQuery.Callbacks( "once memory" ),
+ failList = jQuery.Callbacks( "once memory" ),
+ progressList = jQuery.Callbacks( "memory" ),
+ state = "pending",
+ lists = {
+ resolve: doneList,
+ reject: failList,
+ notify: progressList
+ },
+ promise = {
+ done: doneList.add,
+ fail: failList.add,
+ progress: progressList.add,
+
+ state: function() {
+ return state;
+ },
+
+ // Deprecated
+ isResolved: doneList.fired,
+ isRejected: failList.fired,
+
+ then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
+ return this;
+ },
+ always: function() {
+ deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
+ return this;
+ },
+ pipe: function( fnDone, fnFail, fnProgress ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ],
+ progress: [ fnProgress, "notify" ]
+ }, 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, newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ 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 ) {
+ obj = promise;
+ } else {
+ for ( var key in promise ) {
+ obj[ key ] = promise[ key ];
+ }
+ }
+ return obj;
+ }
+ },
+ deferred = promise.promise({}),
+ key;
+
+ for ( key in lists ) {
+ deferred[ key ] = lists[ key ].fire;
+ deferred[ key + "With" ] = lists[ key ].fireWith;
+ }
+
+ // Handle state
+ deferred.done( function() {
+ state = "resolved";
+ }, failList.disable, progressList.lock ).fail( function() {
+ state = "rejected";
+ }, doneList.disable, progressList.lock );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( firstParam ) {
+ var args = sliceDeferred.call( arguments, 0 ),
+ i = 0,
+ length = args.length,
+ pValues = new Array( length ),
+ count = length,
+ pCount = length,
+ deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+ firstParam :
+ jQuery.Deferred(),
+ promise = deferred.promise();
+ function resolveFunc( i ) {
+ return function( value ) {
+ args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ if ( !( --count ) ) {
+ deferred.resolveWith( deferred, args );
+ }
+ };
+ }
+ function progressFunc( i ) {
+ return function( value ) {
+ pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ deferred.notifyWith( promise, pValues );
+ };
+ }
+ if ( length > 1 ) {
+ for ( ; i < length; i++ ) {
+ if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
+ args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
+ } else {
+ --count;
+ }
+ }
+ if ( !count ) {
+ deferred.resolveWith( deferred, args );
+ }
+ } else if ( deferred !== firstParam ) {
+ deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+ }
+ return promise;
+ }
+});
+
+
+
+
+jQuery.support = (function() {
+
+ var support,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ fragment,
+ tds,
+ events,
+ eventName,
+ i,
+ isSupported,
+ div = document.createElement( "div" ),
+ documentElement = document.documentElement;
+
+ // Preliminary tests
+ div.setAttribute("className", "t");
+ div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+ 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",
+
+ // Tests for enctype support on a form(#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ pixelMargin: true
+ };
+
+ // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
+ jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
+
+ // 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 its 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");
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.lastChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ fragment.removeChild( input );
+ fragment.appendChild( div );
+
+ // Technique from Juriy Zaytsev
+ // http://perfectionkills.com/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;
+ }
+ }
+
+ fragment.removeChild( div );
+
+ // Null elements to avoid leaks in IE
+ fragment = select = opt = div = input = null;
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, outer, inner, table, td, offsetSupport,
+ marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
+ paddingMarginBorderVisibility, paddingMarginBorder,
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ conMarginTop = 1;
+ paddingMarginBorder = "padding:0;margin:0;border:";
+ positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
+ paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
+ style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
+ html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
+ "<table " + style + "' cellpadding='0' cellspacing='0'>" +
+ "<tr><td></td></tr></table>";
+
+ container = document.createElement("div");
+ container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // 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)
+ div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+ 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 );
+
+ // 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 ( window.getComputedStyle ) {
+ div.innerHTML = "";
+ marginDiv = document.createElement( "div" );
+ marginDiv.style.width = "0";
+ marginDiv.style.marginRight = "0";
+ div.style.width = "2px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // 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.innerHTML = "";
+ div.style.width = div.style.padding = "1px";
+ div.style.border = 0;
+ div.style.overflow = "hidden";
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "<div style='width:5px;'></div>";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+ }
+
+ div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
+ div.innerHTML = html;
+
+ outer = div.firstChild;
+ inner = outer.firstChild;
+ td = outer.nextSibling.firstChild.firstChild;
+
+ offsetSupport = {
+ doesNotAddBorder: ( inner.offsetTop !== 5 ),
+ doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
+ };
+
+ inner.style.position = "fixed";
+ inner.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
+ inner.style.position = inner.style.top = "";
+
+ outer.style.overflow = "hidden";
+ outer.style.position = "relative";
+
+ offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
+ offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+
+ if ( window.getComputedStyle ) {
+ div.style.marginTop = "1%";
+ support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+ }
+
+ if ( typeof container.style.zoom !== "undefined" ) {
+ container.style.zoom = 1;
+ }
+
+ body.removeChild( container );
+ marginDiv = div = container = null;
+
+ jQuery.extend( support, offsetSupport );
+ });
+
+ return support;
+})();
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+ rmultiDash = /([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 privateCache, thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // 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,
+ isEvents = name === "events";
+
+ // 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] || (!isEvents && !pvt && !cache[id].data)) && 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[ internalKey ] = id = ++jQuery.uuid;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // 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 ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ privateCache = 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;
+ }
+
+ // Users should not attempt to inspect the internal events object using jQuery.data,
+ // it is undocumented and subject to change. But does anyone listen? No.
+ if ( isEvents && !thisCache[ name ] ) {
+ return privateCache.events;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // 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;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ // Reference to internal data cache key
+ 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[ internalKey ] : internalKey;
+
+ // 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( " " );
+ }
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; 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 : 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;
+ }
+ }
+
+ // 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
+ // Ensure that `cache` is not a window object #10080
+ if ( jQuery.support.deleteExpando || !cache.setInterval ) {
+ delete cache[ id ];
+ } else {
+ cache[ id ] = null;
+ }
+
+ // We destroyed the cache and need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ 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[ internalKey ];
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( internalKey );
+ } else {
+ elem[ internalKey ] = 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 parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.substring(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 );
+ });
+ }
+
+ parts = key.split( ".", 2 );
+ parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ }
+
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
+
+ self.triggerHandler( "setData" + part, parts );
+ jQuery.data( this, key, value );
+ self.triggerHandler( "changeData" + part, parts );
+ });
+ }, null, value, arguments.length > 1, null, false );
+ },
+
+ 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" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ jQuery.isNumeric( 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 ) {
+ for ( var 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 handleQueueMarkDefer( elem, type, src ) {
+ var deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ defer = jQuery._data( elem, deferDataKey );
+ if ( defer &&
+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
+ // 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 ) &&
+ !jQuery._data( elem, markDataKey ) ) {
+ jQuery.removeData( elem, deferDataKey, true );
+ defer.fire();
+ }
+ }, 0 );
+ }
+}
+
+jQuery.extend({
+
+ _mark: function( elem, type ) {
+ if ( elem ) {
+ type = ( type || "fx" ) + "mark";
+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
+ }
+ },
+
+ _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 ) || 1) - 1 );
+ if ( count ) {
+ jQuery._data( elem, key, count );
+ } else {
+ jQuery.removeData( elem, key, true );
+ handleQueueMarkDefer( elem, type, "mark" );
+ }
+ }
+ },
+
+ queue: function( elem, type, data ) {
+ var q;
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ q = jQuery._data( elem, type );
+
+ // 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) );
+ } else {
+ q.push( data );
+ }
+ }
+ return q || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ fn = queue.shift(),
+ hooks = {};
+
+ // 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" );
+ }
+
+ jQuery._data( elem, type + ".run", hooks );
+ fn.call( elem, function() {
+ jQuery.dequeue( elem, type );
+ }, hooks );
+ }
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue " + type + ".run", true );
+ handleQueueMarkDefer( elem, type, "queue" );
+ }
+ }
+});
+
+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 );
+
+ 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( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ 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.Callbacks( "once memory" ), true ) )) {
+ count++;
+ tmp.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( object );
+ }
+});
+
+
+
+
+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,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ nodeHook, boolHook, fixSpecified;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ 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 + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ 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;
+ }
+
+ 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.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // 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, i, max, option,
+ 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
+ i = one ? index : 0;
+ max = one ? index + 1 : options.length;
+ for ( ; i < max; i++ ) {
+ 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
+ },
+
+ attr: function( elem, name, value, pass ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+
+ } 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, value ) {
+ var propName, attrNames, name, l, isBool,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+ attrNames = value.toLowerCase().split( rspace );
+ l = attrNames.length;
+
+ for ( ; i < l; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
+ elem.removeAttribute( getSetAttribute ? name : propName );
+
+ // Set corresponding property to false for boolean attributes
+ if ( isBool && propName 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;
+ }
+ }
+ },
+ // Use the value property for back compat
+ // Use the nodeHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.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 ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ 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 )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ 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;
+ }
+ }
+ }
+});
+
+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+ 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 ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true,
+ coords: true
+ };
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
+ ret.nodeValue :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
+ }
+ return ( ret.nodeValue = value + "" );
+ }
+ };
+
+ // Apply the nodeHook to tabindex
+ jQuery.attrHooks.tabindex.set = nodeHook.set;
+
+ // 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;
+ }
+ }
+ });
+ });
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
+}
+
+
+// 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;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// 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 rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+ rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
+ quickParse = function( selector ) {
+ var quick = rquickIs.exec( selector );
+ if ( quick ) {
+ // 0 1 2 3
+ // [ _, tag, id, class ]
+ quick[1] = ( quick[1] || "" ).toLowerCase();
+ quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
+ }
+ return quick;
+ },
+ quickIs = function( elem, m ) {
+ var attrs = elem.attributes || {};
+ return (
+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+ (!m[2] || (attrs.id || {}).value === m[2]) &&
+ (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
+ );
+ },
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, quick, handlers, special;
+
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+ 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
+ events = elemData.events;
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+ eventHandle = elemData.handle;
+ 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.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
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
+
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+ // 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: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ quick: selector && quickParse( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
+ if ( !handlers ) {
+ 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;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ t, tns, type, origType, namespaces, origCount,
+ j, events, special, handle, eventType, handleObj;
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
+
+ // 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;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
+
+ if ( handleObj.selector ) {
+ eventType.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 ( eventType.length === 0 && origCount !== eventType.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, [ "events", "handle" ], 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 ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
+ // Event object or event type
+ var type = event.type || event,
+ namespaces = [],
+ cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
+
+ // 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 ) {
+ // 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.isTrigger = true;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+ // Handle a global trigger
+ if ( !elem ) {
+
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+ }
+ }
+ return;
+ }
+
+ // 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 ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( 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)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ old = null;
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old && old === elem.ownerDocument ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === 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( elem.ownerDocument, data ) === 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.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event || window.event );
+
+ var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = [].slice.call( arguments, 0 ),
+ run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
+ handlerQueue = [],
+ i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
+
+ // 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 that should run if there are delegated events
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
+
+ // Pregenerate a single jQuery object for reuse with .is()
+ jqcur = jQuery(this);
+ jqcur.context = this.ownerDocument || this;
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't process events on disabled elements (#6911, #8165)
+ if ( cur.disabled !== true ) {
+ selMatch = {};
+ matches = [];
+ jqcur[0] = cur;
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = (
+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+ );
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( 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;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement 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 eventDoc, doc, body,
+ 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;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = jQuery.Event( originalEvent );
+
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Target should not be a text node (#504, Safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady
+ },
+
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
+ },
+
+ 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;
+ }
+ }
+ }
+ },
+
+ 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();
+ }
+ }
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+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 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.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 );
+ }
+
+ // 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;
+};
+
+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
+};
+
+// 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 target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector,
+ ret;
+
+ // 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 ( !jQuery.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 && !form._submit_attached ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ form._submit_attached = 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 ( !jQuery.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;
+ 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 ) && !elem._change_attached ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ elem._change_attached = 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 ( !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,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) { // && selector != null
+ // ( 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 ) {
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ var 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 ( var 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 );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
+ },
+
+ 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 );
+ }
+});
+
+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 contextmenu").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.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
+
+
+
+/*!
+ * 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,
+ expando = "sizcache" + (Math.random() + '').replace('.', ''),
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rReturn = /\r\n/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, seed );
+
+ } 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, seed );
+ }
+ }
+
+ } 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, i, len, match, type, left;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ 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,
+ type, found, item, filter, left,
+ i, pass,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ 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 ( i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ 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 new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Utility function for retreiving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+var getText = Sizzle.getText = function( elem ) {
+ var i, node,
+ nodeType = elem.nodeType,
+ ret = "";
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent || innerText for elements
+ if ( typeof elem.textContent === 'string' ) {
+ return elem.textContent;
+ } else if ( typeof elem.innerText === 'string' ) {
+ // Replace IE's carriage returns
+ return elem.innerText.replace( rReturn, '' );
+ } else {
+ // Traverse it's children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( i = 0; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ if ( node.nodeType !== 8 ) {
+ ret += getText( node );
+ }
+ }
+ }
+ return ret;
+};
+
+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 || 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 first, last,
+ doneName, parent, cache,
+ count, diff,
+ 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;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ first = match[2];
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ doneName = match[0];
+ parent = elem.parentNode;
+
+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+ count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent[ expando ] = doneName;
+ }
+
+ 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 && 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 = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ 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 && Sizzle.attr ?
+ result != null :
+ 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) );
+}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
+
+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;
+ };
+}
+
+// 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 = "<a name='" + id + "'/>";
+
+ // 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 = "<a href='#'></a>";
+
+ 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 = "<p class='TEST'></p>";
+
+ // 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 = "<div class='test e'></div><div class='test'></div>";
+
+ // 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[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem[ expando ] = 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[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem[ expando ] = 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, seed ) {
+ 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, seed );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
+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.globalPOS,
+ // 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" ?
+ // If this is a positional selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ POS.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
+ // Array (deprecated as of jQuery 1.7)
+ if ( jQuery.isArray( selectors ) ) {
+ var level = 1;
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( i = 0; i < selectors.length; i++ ) {
+
+ if ( jQuery( cur ).is( selectors[ i ] ) ) {
+ ret.push({ selector: selectors[ i ], 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 ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.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 ) {
+ 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 );
+
+ 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, slice.call( arguments ).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;
+ });
+}
+
+
+
+
+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+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style)/i,
+ rnocache = /<(?:script|object|embed|option|style)/i,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ area: [ 1, "<map>", "</map>" ],
+ _default: [ 0, "", "" ]
+ },
+ safeFragment = createSafeFragment( document );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.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 );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ } else if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ set.push.apply( set, this.toArray() );
+ return this.pushStack( set, "before", arguments );
+ }
+ },
+
+ after: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ } else if ( arguments.length ) {
+ var set = this.pushStack( this, "after", arguments );
+ set.push.apply( set, jQuery.clean(arguments) );
+ return set;
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ 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 jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ null;
+ }
+
+
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ 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( value ) {
+ if ( this[0] && this[0].parentNode ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ } else {
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ }
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+ var results, first, fragment, parent,
+ value = args[0],
+ scripts = [];
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback, true );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call(this, i, table ? self.html() : undefined);
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ parent = value && value.parentNode;
+
+ // If we're in a fragment, just use that instead of building a new one
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
+ } else {
+ results = jQuery.buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+ callback.call(
+ table ?
+ root(this[i], first) :
+ this[i],
+ // Make sure that we do not leak memory by inadvertently discarding
+ // the original fragment (which might have attached data) instead of
+ // using it; in addition, use the original fragment object for the last
+ // item instead of first because it can end up being emptied incorrectly
+ // in certain situations (Bug #8070).
+ // Fragments from the fragment cache must always be cloned and never used
+ // in place.
+ results.cacheable || ( l > 1 && i < lastIndex ) ?
+ jQuery.clone( fragment, true, true ) :
+ fragment
+ );
+ }
+ }
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ type: "GET",
+ global: false,
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
+ }
+ }
+
+ return this;
+ }
+});
+
+function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+}
+
+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 cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 fail to clone children inside object elements that use
+ // the proprietary classid attribute value (rather than the type
+ // attribute) to identify the type of content to display
+ if ( nodeName === "object" ) {
+ dest.outerHTML = src.outerHTML;
+
+ } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+ // 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
+ if ( src.checked ) {
+ 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.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;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+
+ // Clear flags for bubbling special change/submit events, they must
+ // be reattached when the newly cloned events are first activated
+ dest.removeAttribute( "_submit_attached" );
+ dest.removeAttribute( "_change_attached" );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults, doc,
+ first = args[ 0 ];
+
+ // nodes may contain either an explicit document object,
+ // a jQuery collection or context object.
+ // If nodes[0] contains a valid object to assign to doc
+ if ( nodes && nodes[0] ) {
+ doc = nodes[0].ownerDocument || nodes[0];
+ }
+
+ // Ensure that an attr object doesn't incorrectly stand in as a document object
+ // Chrome and Firefox seem to allow this to occur and will throw exception
+ // Fixes #8950
+ if ( !doc.createDocumentFragment ) {
+ doc = document;
+ }
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+ cacheable = true;
+
+ cacheresults = jQuery.fragments[ first ];
+ if ( cacheresults && cacheresults !== 1 ) {
+ fragment = cacheresults;
+ }
+ }
+
+ if ( !fragment ) {
+ fragment = doc.createDocumentFragment();
+ jQuery.clean( args, doc, fragment, scripts );
+ }
+
+ if ( cacheable ) {
+ jQuery.fragments[ first ] = cacheresults ? fragment : 1;
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = [],
+ insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = ( i > 0 ? this.clone(true) : this ).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( elem.type === "checkbox" || elem.type === "radio" ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "input" ) {
+ fixDefaultChecked( elem );
+ // Skip scripts, get other children
+ } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+}
+
+// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
+function shimCloneNode( elem ) {
+ var div = document.createElement( "div" );
+ safeFragment.appendChild( div );
+
+ div.innerHTML = elem.outerHTML;
+ return div.firstChild;
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var srcElements,
+ destElements,
+ i,
+ // IE<=8 does not properly clone detached, unknown element nodes
+ clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
+ elem.cloneNode( true ) :
+ shimCloneNode( elem );
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var checkScriptType, script, j,
+ ret = [];
+
+ context = context || document;
+
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if ( typeof context.createElement === "undefined" ) {
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+ }
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
+ wrap = wrapMap[ tag ] || wrapMap._default,
+ depth = wrap[0],
+ div = context.createElement("div"),
+ safeChildNodes = safeFragment.childNodes,
+ remove;
+
+ // Append wrapper element to unknown element safe doc fragment
+ if ( context === document ) {
+ // Use the fragment we've already created for this document
+ safeFragment.appendChild( div );
+ } else {
+ // Use a fragment created with the owner document
+ createSafeFragment( context ).appendChild( div );
+ }
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var hasBody = rtbody.test(elem),
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+
+ // Clear elements from DocumentFragment (safeFragment or otherwise)
+ // to avoid hoarding elements. Fixes #11356
+ if ( div ) {
+ div.parentNode.removeChild( div );
+
+ // Guard against -1 index exceptions in FF3.6
+ if ( safeChildNodes.length > 0 ) {
+ remove = safeChildNodes[ safeChildNodes.length - 1 ];
+
+ if ( remove && remove.parentNode ) {
+ remove.parentNode.removeChild( remove );
+ }
+ }
+ }
+ }
+ }
+
+ // Resets defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ var len;
+ if ( !jQuery.support.appendChecked ) {
+ if ( elem[0] && typeof (len = elem.length) === "number" ) {
+ for ( j = 0; j < len; j++ ) {
+ findInputs( elem[j] );
+ }
+ } else {
+ findInputs( elem );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ ret = jQuery.merge( ret, elem );
+ }
+ }
+
+ if ( fragment ) {
+ checkScriptType = function( elem ) {
+ return !elem.type || rscriptType.test( elem.type );
+ };
+ for ( i = 0; ret[i]; i++ ) {
+ script = ret[i];
+ if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
+ scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
+
+ } else {
+ if ( script.nodeType === 1 ) {
+ var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
+
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ }
+ fragment.appendChild( script );
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems ) {
+ var data, id,
+ cache = jQuery.cache,
+ special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ continue;
+ }
+
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ];
+
+ if ( data && data.events ) {
+ for ( var 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 );
+ }
+ }
+
+ // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+ if ( data.handle ) {
+ data.handle.elem = null;
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
+ }
+ }
+});
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ // fixed for IE9, see #8346
+ rupper = /([A-Z]|^ms)/g,
+ rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
+ rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
+ rrelNum = /^([\-+])=([\-+.\de]+)/,
+ rmargin = /^margin/,
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+
+ // order is important!
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+
+ curCSS,
+
+ getComputedStyle,
+ currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+};
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+
+ } else {
+ return elem.style.opacity;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, origName = jQuery.camelCase( name ),
+ style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+ name = jQuery.cssProps[ origName ] || origName;
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra ) {
+ var ret, hooks;
+
+ // Make sure that we're working with the right name
+ name = jQuery.camelCase( name );
+ hooks = jQuery.cssHooks[ name ];
+ name = jQuery.cssProps[ name ] || name;
+
+ // cssFloat needs a special treatment
+ if ( name === "cssFloat" ) {
+ name = "float";
+ }
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+ return ret;
+
+ // Otherwise, if a way to get the computed value exists, use that
+ } else if ( curCSS ) {
+ return curCSS( elem, name );
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {},
+ ret, name;
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// DEPRECATED in 1.3, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ getComputedStyle = function( elem, name ) {
+ var ret, defaultView, computedStyle, width,
+ style = elem.style;
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ if ( (defaultView = elem.ownerDocument.defaultView) &&
+ (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
+ // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
+ width = style.width;
+ style.width = ret;
+ ret = computedStyle.width;
+ style.width = width;
+ }
+
+ return ret;
+ };
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left, rsLeft, uncomputed,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && (uncomputed = style[ name ]) ) {
+ ret = uncomputed;
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( rnumnonpx.test( ret ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ i = name === "width" ? 1 : 0,
+ len = 4;
+
+ if ( val > 0 ) {
+ if ( extra !== "border" ) {
+ for ( ; i < len; i += 2 ) {
+ if ( !extra ) {
+ val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
+ } else {
+ val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+ }
+
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+
+ // Add padding, border, margin
+ if ( extra ) {
+ for ( ; i < len; i += 2 ) {
+ val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ if ( extra !== "padding" ) {
+ val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ if ( elem.offsetWidth !== 0 ) {
+ return getWidthOrHeight( elem, name, extra );
+ } else {
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ });
+ }
+ }
+ },
+
+ set: function( elem, value ) {
+ return rnum.test( value ) ?
+ value + "px" :
+ value;
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery(function() {
+ // This hook cannot be added until DOM ready because the support test
+ // for it is not run until after DOM ready
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ return curCSS( elem, "margin-right" );
+ } else {
+ return elem.style.marginRight;
+ }
+ });
+ }
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ var width = elem.offsetWidth,
+ height = elem.offsetHeight;
+
+ return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+});
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ rselectTextarea = /^(?:select|textarea)/i,
+ rspacesAjax = /\s+/,
+ rts = /([?&])_=[^&]*/,
+ rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Document location
+ ajaxLocation,
+
+ // Document location segments
+ ajaxLocParts,
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ if ( jQuery.isFunction( func ) ) {
+ var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+ i = 0,
+ length = dataTypes.length,
+ dataType,
+ list,
+ placeBefore;
+
+ // For each dataType in the dataTypeExpression
+ for ( ; i < length; i++ ) {
+ dataType = dataTypes[ i ];
+ // We control if we're asked to add before
+ // any existing element
+ placeBefore = /^\+/.test( dataType );
+ if ( placeBefore ) {
+ dataType = dataType.substr( 1 ) || "*";
+ }
+ list = structure[ dataType ] = structure[ dataType ] || [];
+ // then we add to the structure accordingly
+ list[ placeBefore ? "unshift" : "push" ]( func );
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+ dataType /* internal */, inspected /* internal */ ) {
+
+ dataType = dataType || options.dataTypes[ 0 ];
+ inspected = inspected || {};
+
+ inspected[ dataType ] = true;
+
+ var list = structure[ dataType ],
+ i = 0,
+ length = list ? list.length : 0,
+ executeOnly = ( structure === prefilters ),
+ selection;
+
+ for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+ selection = list[ i ]( options, originalOptions, jqXHR );
+ // If we got redirected to another dataType
+ // we try there if executing only and not done already
+ if ( typeof selection === "string" ) {
+ if ( !executeOnly || inspected[ selection ] ) {
+ selection = undefined;
+ } else {
+ options.dataTypes.unshift( selection );
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, selection, inspected );
+ }
+ }
+ }
+ // If we're only executing or nothing was selected
+ // we try the catchall dataType if not done already
+ if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, "*", inspected );
+ }
+ // unnecessary when only executing (prefilters)
+ // but it'll be ignored by the caller in that case
+ return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+}
+
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+
+ // Don't do a request if no elements are being requested
+ } else if ( !this.length ) {
+ return this;
+ }
+
+ var off = url.indexOf( " " );
+ if ( off >= 0 ) {
+ var selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params ) {
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( typeof params === "object" ) {
+ params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+ type = "POST";
+ }
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ // Complete callback (responseText is used internally)
+ complete: function( jqXHR, status, responseText ) {
+ // Store the response as specified by the jqXHR object
+ responseText = jqXHR.responseText;
+ // If successful, inject the HTML into all the matched elements
+ if ( jqXHR.isResolved() ) {
+ // #4825: Get the actual response in case
+ // a dataFilter is present in ajaxSettings
+ jqXHR.done(function( r ) {
+ responseText = r;
+ });
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(responseText.replace(rscript, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ responseText );
+ }
+
+ if ( callback ) {
+ self.each( callback, [ responseText, status, jqXHR ] );
+ }
+ }
+ });
+
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+ jQuery.fn[ o ] = function( f ){
+ return this.on( o, f );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ type: method,
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ };
+});
+
+jQuery.extend({
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ if ( settings ) {
+ // Building a settings object
+ ajaxExtend( target, jQuery.ajaxSettings );
+ } else {
+ // Extending ajaxSettings
+ settings = target;
+ target = jQuery.ajaxSettings;
+ }
+ ajaxExtend( target, settings );
+ return target;
+ },
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ type: "GET",
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ processData: true,
+ async: true,
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ text: "text/plain",
+ json: "application/json, text/javascript",
+ "*": allTypes
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // List of data converters
+ // 1) key format is "source_type destination_type" (a single space in-between)
+ // 2) the catchall symbol "*" can be used for source_type
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ context: true,
+ url: true
+ }
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events
+ // It's the callbackContext if one was provided in the options
+ // and if it's a DOM node or a jQuery collection
+ globalEventContext = callbackContext !== s &&
+ ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+ jQuery( callbackContext ) : jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // ifModified key
+ ifModifiedKey,
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // transport
+ transport,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // The jqXHR state
+ state = 0,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Fake xhr
+ jqXHR = {
+
+ readyState: 0,
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( !state ) {
+ var lname = name.toLowerCase();
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match === undefined ? null : match;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ statusText = statusText || "abort";
+ if ( transport ) {
+ transport.abort( statusText );
+ }
+ done( 0, statusText );
+ return this;
+ }
+ };
+
+ // Callback for when everything is done
+ // It is defined here because jslint complains if it is declared
+ // at the end of the function (which would be more logical and readable)
+ function done( status, nativeStatusText, responses, headers ) {
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ var isSuccess,
+ success,
+ error,
+ statusText = nativeStatusText,
+ response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+ lastModified,
+ etag;
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+
+ if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+ jQuery.lastModified[ ifModifiedKey ] = lastModified;
+ }
+ if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+ jQuery.etag[ ifModifiedKey ] = etag;
+ }
+ }
+
+ // If not modified
+ if ( status === 304 ) {
+
+ statusText = "notmodified";
+ isSuccess = true;
+
+ // If we have data
+ } else {
+
+ try {
+ success = ajaxConvert( s, response );
+ statusText = "success";
+ isSuccess = true;
+ } catch(e) {
+ // We have a parsererror
+ statusText = "parsererror";
+ error = e;
+ }
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( !statusText || status ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = "" + ( nativeStatusText || statusText );
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+ jqXHR.complete = completeDeferred.add;
+
+ // Status-dependent callbacks
+ jqXHR.statusCode = function( map ) {
+ if ( map ) {
+ var tmp;
+ if ( state < 2 ) {
+ for ( tmp in map ) {
+ statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+ }
+ } else {
+ tmp = map[ jqXHR.status ];
+ jqXHR.then( tmp, tmp );
+ }
+ }
+ return this;
+ };
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+ // Determine if a cross-domain request is in order
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return false;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Get ifModifiedKey before adding the anti-cache parameter
+ ifModifiedKey = s.url;
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+
+ var ts = jQuery.now(),
+ // try replacing _= if it is there
+ ret = s.url.replace( rts, "$1_=" + ts );
+
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ ifModifiedKey = ifModifiedKey || s.url;
+ if ( jQuery.lastModified[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+ }
+ if ( jQuery.etag[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+ }
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already
+ jqXHR.abort();
+ return false;
+
+ }
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout( function(){
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch (e) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : value;
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+ }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( var name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields,
+ ct,
+ type,
+ finalDataType,
+ firstDataType;
+
+ // Fill responseXXX fields
+ for ( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ var dataTypes = s.dataTypes,
+ converters = {},
+ i,
+ key,
+ length = dataTypes.length,
+ tmp,
+ // Current and previous dataTypes
+ current = dataTypes[ 0 ],
+ prev,
+ // Conversion expression
+ conversion,
+ // Conversion function
+ conv,
+ // Conversion functions (transitive conversion)
+ conv1,
+ conv2;
+
+ // For each dataType in the chain
+ for ( i = 1; i < length; i++ ) {
+
+ // Create converters map
+ // with lowercased keys
+ if ( i === 1 ) {
+ for ( key in s.converters ) {
+ if ( typeof key === "string" ) {
+ converters[ key.toLowerCase() ] = s.converters[ key ];
+ }
+ }
+ }
+
+ // Get the dataTypes
+ prev = current;
+ current = dataTypes[ i ];
+
+ // If current is auto dataType, update it to prev
+ if ( current === "*" ) {
+ current = prev;
+ // If no auto and dataTypes are actually different
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Get the converter
+ conversion = prev + " " + current;
+ conv = converters[ conversion ] || converters[ "* " + current ];
+
+ // If there is no direct converter, search transitively
+ if ( !conv ) {
+ conv2 = undefined;
+ for ( conv1 in converters ) {
+ tmp = conv1.split( " " );
+ if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+ conv2 = converters[ tmp[1] + " " + current ];
+ if ( conv2 ) {
+ conv1 = converters[ conv1 ];
+ if ( conv1 === true ) {
+ conv = conv2;
+ } else if ( conv2 === true ) {
+ conv = conv1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ // If we found no converter, dispatch an error
+ if ( !( conv || conv2 ) ) {
+ jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+ }
+ // If found converter is not an equivalence
+ if ( conv !== true ) {
+ // Convert with 1 or 2 converters accordingly
+ response = conv ? conv( response ) : conv2( conv1(response) );
+ }
+ }
+ }
+ return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+ jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ return jQuery.expando + "_" + ( jsc++ );
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
+
+ if ( s.dataTypes[ 0 ] === "jsonp" ||
+ s.jsonp !== false && ( jsre.test( s.url ) ||
+ inspectData && jsre.test( s.data ) ) ) {
+
+ var responseContainer,
+ jsonpCallback = s.jsonpCallback =
+ jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+ previous = window[ jsonpCallback ],
+ url = s.url,
+ data = s.data,
+ replace = "$1" + jsonpCallback + "$2";
+
+ if ( s.jsonp !== false ) {
+ url = url.replace( jsre, replace );
+ if ( s.url === url ) {
+ if ( inspectData ) {
+ data = data.replace( jsre, replace );
+ }
+ if ( s.data === data ) {
+ // Add callback manually
+ url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ }
+ }
+ }
+
+ s.url = url;
+ s.data = data;
+
+ // Install callback
+ window[ jsonpCallback ] = function( response ) {
+ responseContainer = [ response ];
+ };
+
+ // Clean-up function
+ jqXHR.always(function() {
+ // Set callback back to previous value
+ window[ jsonpCallback ] = previous;
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( previous ) ) {
+ window[ jsonpCallback ]( responseContainer[ 0 ] );
+ }
+ });
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( jsonpCallback + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /javascript|ecmascript/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement( "script" );
+
+ script.async = "async";
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( head && script.parentNode ) {
+ head.removeChild( script );
+ }
+
+ // Dereference the script
+ script = undefined;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709 and #4378).
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( 0, 1 );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject ? function() {
+ // Abort all pending requests
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( 0, 1 );
+ }
+ } : false,
+ xhrId = 0,
+ xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+ jQuery.extend( jQuery.support, {
+ ajax: !!xhr,
+ cors: !!xhr && ( "withCredentials" in xhr )
+ });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var xhr = s.xhr(),
+ handle,
+ i;
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( _ ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+
+ var status,
+ statusText,
+ responseHeaders,
+ responses,
+ xml;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occured
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+ responses = {};
+ xml = xhr.responseXML;
+
+ // Construct response list
+ if ( xml && xml.documentElement /* #4958 */ ) {
+ responses.xml = xml;
+ }
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ try {
+ responses.text = xhr.responseText;
+ } catch( _ ) {
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ // if we're in sync mode or it's in cache
+ // and has been retrieved directly (IE6 & IE7)
+ // we need to manually fire the callback
+ if ( !s.async || xhr.readyState === 4 ) {
+ callback();
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback(0,1);
+ }
+ }
+ };
+ }
+ });
+}
+
+
+
+
+var elemdisplay = {},
+ iframe, iframeDoc,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+ timerId,
+ fxAttrs = [
+ // height animations
+ [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+ // width animations
+ [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+ // opacity animations
+ [ "opacity" ]
+ ],
+ fxNow;
+
+jQuery.fn.extend({
+ show: function( speed, easing, callback ) {
+ var elem, display;
+
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("show", 3), speed, easing, callback );
+
+ } else {
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+ display = elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+ !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ if ( display === "" || display === "none" ) {
+ elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
+ }
+ }
+ }
+
+ return this;
+ }
+ },
+
+ hide: function( speed, easing, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("hide", 3), speed, easing, callback);
+
+ } else {
+ var elem, display,
+ i = 0,
+ j = this.length;
+
+ for ( ; i < j; i++ ) {
+ elem = this[i];
+ if ( elem.style ) {
+ display = jQuery.css( elem, "display" );
+
+ if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+ jQuery._data( elem, "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ if ( this[i].style ) {
+ this[i].style.display = "none";
+ }
+ }
+
+ return this;
+ }
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2, callback ) {
+ var bool = typeof fn === "boolean";
+
+ if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+ this._toggle.apply( this, arguments );
+
+ } else if ( fn == null || bool ) {
+ this.each(function() {
+ var state = bool ? fn : jQuery(this).is(":hidden");
+ jQuery(this)[ state ? "show" : "hide" ]();
+ });
+
+ } else {
+ this.animate(genFx("toggle", 3), fn, fn2, callback);
+ }
+
+ return this;
+ },
+
+ fadeTo: function( speed, to, easing, callback ) {
+ return this.filter(":hidden").css("opacity", 0).show().end()
+ .animate({opacity: to}, speed, easing, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed( speed, easing, callback );
+
+ if ( jQuery.isEmptyObject( prop ) ) {
+ return this.each( optall.complete, [ false ] );
+ }
+
+ // Do not change referenced properties as per-property easing will be lost
+ prop = jQuery.extend( {}, prop );
+
+ function doAnimation() {
+ // XXX 'this' does not always have a nodeName when running the
+ // test suite
+
+ if ( optall.queue === false ) {
+ jQuery._mark( this );
+ }
+
+ var opt = jQuery.extend( {}, optall ),
+ isElement = this.nodeType === 1,
+ hidden = isElement && jQuery(this).is(":hidden"),
+ name, val, p, e, hooks, replace,
+ parts, start, end, unit,
+ method;
+
+ // will store per property easing and be used to determine when an animation is complete
+ opt.animatedProperties = {};
+
+ // first pass over propertys to expand / normalize
+ for ( p in prop ) {
+ name = jQuery.camelCase( p );
+ if ( p !== name ) {
+ prop[ name ] = prop[ p ];
+ delete prop[ p ];
+ }
+
+ if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+ replace = hooks.expand( prop[ name ] );
+ delete prop[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'p' from above because we have the correct "name"
+ for ( p in replace ) {
+ if ( ! ( p in prop ) ) {
+ prop[ p ] = replace[ p ];
+ }
+ }
+ }
+ }
+
+ for ( name in prop ) {
+ val = prop[ name ];
+ // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+ if ( jQuery.isArray( val ) ) {
+ opt.animatedProperties[ name ] = val[ 1 ];
+ val = prop[ name ] = val[ 0 ];
+ } else {
+ opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+ }
+
+ if ( val === "hide" && hidden || val === "show" && !hidden ) {
+ return opt.complete.call( this );
+ }
+
+ if ( isElement && ( name === "height" || name === "width" ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( this, "display" ) === "inline" &&
+ jQuery.css( this, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
+ this.style.display = "inline-block";
+
+ } else {
+ this.style.zoom = 1;
+ }
+ }
+ }
+ }
+
+ if ( opt.overflow != null ) {
+ this.style.overflow = "hidden";
+ }
+
+ for ( p in prop ) {
+ e = new jQuery.fx( this, opt, p );
+ val = prop[ p ];
+
+ if ( rfxtypes.test( val ) ) {
+
+ // Tracks whether to show or hide based on private
+ // data attached to the element
+ method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+ if ( method ) {
+ jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+ e[ method ]();
+ } else {
+ e[ val ]();
+ }
+
+ } else {
+ parts = rfxnum.exec( val );
+ start = e.cur();
+
+ if ( parts ) {
+ end = parseFloat( parts[2] );
+ unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" ) {
+ jQuery.style( this, p, (end || 1) + unit);
+ start = ( (end || 1) / e.cur() ) * start;
+ jQuery.style( this, p, start + unit);
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] ) {
+ end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+ }
+
+ e.custom( start, end, unit );
+
+ } else {
+ e.custom( start, val, "" );
+ }
+ }
+ }
+
+ // For JS strict compliance
+ return true;
+ }
+
+ return optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+
+ stop: function( type, clearQueue, gotoEnd ) {
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var index,
+ hadTimers = false,
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ // clear marker counters if we know they won't be
+ if ( !gotoEnd ) {
+ jQuery._unmark( true, this );
+ }
+
+ function stopQueue( elem, data, index ) {
+ var hooks = data[ index ];
+ jQuery.removeData( elem, index, true );
+ hooks.stop( gotoEnd );
+ }
+
+ if ( type == null ) {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+ stopQueue( this, data, index );
+ }
+ }
+ } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+ stopQueue( this, data, index );
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ if ( gotoEnd ) {
+
+ // force the next step to be the last
+ timers[ index ]( true );
+ } else {
+ timers[ index ].saveState();
+ }
+ hadTimers = true;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( !( gotoEnd && hadTimers ) ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout( clearFxNow, 0 );
+ return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+ fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx( "show", 1 ),
+ slideUp: genFx( "hide", 1 ),
+ slideToggle: genFx( "toggle", 1 ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.extend({
+ speed: function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function( noUnmark ) {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ } else if ( noUnmark !== false ) {
+ jQuery._unmark( this );
+ }
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+ }
+ },
+
+ timers: [],
+
+ fx: function( elem, options, prop ) {
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ options.orig = options.orig || {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+ // Simple function for setting a style value
+ update: function() {
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
+ },
+
+ // Get the current size
+ cur: function() {
+ if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
+ return this.elem[ this.prop ];
+ }
+
+ var parsed,
+ r = jQuery.css( this.elem, this.prop );
+ // Empty strings, null, undefined and "auto" are converted to 0,
+ // complex values such as "rotate(1rad)" are returned as is,
+ // simple values such as "10px" are parsed to Float.
+ return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+ },
+
+ // Start an animation from one number to another
+ custom: function( from, to, unit ) {
+ var self = this,
+ fx = jQuery.fx;
+
+ this.startTime = fxNow || createFxNow();
+ this.end = to;
+ this.now = this.start = from;
+ this.pos = this.state = 0;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+
+ function t( gotoEnd ) {
+ return self.step( gotoEnd );
+ }
+
+ t.queue = this.options.queue;
+ t.elem = this.elem;
+ t.saveState = function() {
+ if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ if ( self.options.hide ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ } else if ( self.options.show ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+ }
+ }
+ };
+
+ if ( t() && jQuery.timers.push(t) && !timerId ) {
+ timerId = setInterval( fx.tick, fx.interval );
+ }
+ },
+
+ // Simple 'show' function
+ show: function() {
+ var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ // Make sure that we start at a small width/height to avoid any flash of content
+ if ( dataShow !== undefined ) {
+ // This show is picking up where a previous hide or show left off
+ this.custom( this.cur(), dataShow );
+ } else {
+ this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+ }
+
+ // Start by showing the element
+ jQuery( this.elem ).show();
+ },
+
+ // Simple 'hide' function
+ hide: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom( this.cur(), 0 );
+ },
+
+ // Each step of an animation
+ step: function( gotoEnd ) {
+ var p, n, complete,
+ t = fxNow || createFxNow(),
+ done = true,
+ elem = this.elem,
+ options = this.options;
+
+ if ( gotoEnd || t >= options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ options.animatedProperties[ this.prop ] = true;
+
+ for ( p in options.animatedProperties ) {
+ if ( options.animatedProperties[ p ] !== true ) {
+ done = false;
+ }
+ }
+
+ if ( done ) {
+ // Reset the overflow
+ if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+ jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+ elem.style[ "overflow" + value ] = options.overflow[ index ];
+ });
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( options.hide ) {
+ jQuery( elem ).hide();
+ }
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( options.hide || options.show ) {
+ for ( p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[ p ] );
+ jQuery.removeData( elem, "fxshow" + p, true );
+ // Toggle data is no longer needed
+ jQuery.removeData( elem, "toggle" + p, true );
+ }
+ }
+
+ // Execute the complete function
+ // in the event that the complete function throws an exception
+ // we must ensure it won't be called twice. #5684
+
+ complete = options.complete;
+ if ( complete ) {
+
+ options.complete = false;
+ complete.call( elem );
+ }
+ }
+
+ return false;
+
+ } else {
+ // classical easing cannot be used with an Infinity duration
+ if ( options.duration == Infinity ) {
+ this.now = t;
+ } else {
+ n = t - this.startTime;
+ this.state = n / options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ( (this.end - this.start) * this.pos );
+ }
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+};
+
+jQuery.extend( jQuery.fx, {
+ tick: function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ },
+
+ interval: 13,
+
+ stop: function() {
+ clearInterval( timerId );
+ timerId = null;
+ },
+
+ speeds: {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+ },
+
+ step: {
+ opacity: function( fx ) {
+ jQuery.style( fx.elem, "opacity", fx.now );
+ },
+
+ _default: function( fx ) {
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ } else {
+ fx.elem[ fx.prop ] = fx.now;
+ }
+ }
+ }
+});
+
+// Ensure props that can't be negative don't go there on undershoot easing
+jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+ // exclude marginTop, marginLeft, marginBottom and marginRight from this list
+ if ( prop.indexOf( "margin" ) ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+ if ( !elemdisplay[ nodeName ] ) {
+
+ var body = document.body,
+ elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+ display = elem.css( "display" );
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // No iframe to use yet, so create it
+ if ( !iframe ) {
+ iframe = document.createElement( "iframe" );
+ iframe.frameBorder = iframe.width = iframe.height = 0;
+ }
+
+ body.appendChild( iframe );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.createElement( nodeName );
+
+ iframeDoc.body.appendChild( elem );
+
+ display = jQuery.css( elem, "display" );
+ body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return elemdisplay[ nodeName ];
+}
+
+
+
+
+var getOffset,
+ rtable = /^t(?:able|d|h)$/i,
+ rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+ getOffset = function( elem, doc, docElem, box ) {
+ try {
+ box = elem.getBoundingClientRect();
+ } catch(e) {}
+
+ // Make sure we're not dealing with a disconnected DOM node
+ if ( !box || !jQuery.contains( docElem, elem ) ) {
+ return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+ }
+
+ var body = doc.body,
+ win = getWindow( doc ),
+ clientTop = docElem.clientTop || body.clientTop || 0,
+ clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
+ scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+ top = box.top + scrollTop - clientTop,
+ left = box.left + scrollLeft - clientLeft;
+
+ return { top: top, left: left };
+ };
+
+} else {
+ getOffset = function( elem, doc, docElem ) {
+ var computedStyle,
+ offsetParent = elem.offsetParent,
+ prevOffsetParent = elem,
+ body = doc.body,
+ defaultView = doc.defaultView,
+ prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+ top = elem.offsetTop,
+ left = elem.offsetLeft;
+
+ while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ break;
+ }
+
+ computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+ top -= elem.scrollTop;
+ left -= elem.scrollLeft;
+
+ if ( elem === offsetParent ) {
+ top += elem.offsetTop;
+ left += elem.offsetLeft;
+
+ if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevOffsetParent = offsetParent;
+ offsetParent = elem.offsetParent;
+ }
+
+ if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevComputedStyle = computedStyle;
+ }
+
+ if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+ top += body.offsetTop;
+ left += body.offsetLeft;
+ }
+
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ top += Math.max( docElem.scrollTop, body.scrollTop );
+ left += Math.max( docElem.scrollLeft, body.scrollLeft );
+ }
+
+ return { top: top, left: left };
+ };
+}
+
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var elem = this[0],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return null;
+ }
+
+ if ( elem === doc.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ return getOffset( elem, doc, doc.documentElement );
+};
+
+jQuery.offset = {
+
+ bodyOffset: function( body ) {
+ var top = body.offsetTop,
+ left = body.offsetLeft;
+
+ if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+ top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+ left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+ }
+
+ return { top: top, left: left };
+ },
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[0] ) {
+ return null;
+ }
+
+ var elem = this[0],
+
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+ offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+ // Add offsetParent borders
+ parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+ parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+ // Subtract the two offsets
+ return {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.body;
+ while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ var clientProp = "client" + name,
+ scrollProp = "scroll" + name,
+ offsetProp = "offset" + name;
+
+ // innerHeight and innerWidth
+ jQuery.fn[ "inner" + name ] = function() {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, "padding" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn[ "outer" + name ] = function( margin ) {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ jQuery.fn[ type ] = function( value ) {
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc, docElemProp, orig, ret;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+ doc = elem.document;
+ docElemProp = doc.documentElement[ clientProp ];
+ return jQuery.support.boxModel && docElemProp ||
+ doc.body && doc.body[ clientProp ] || docElemProp;
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ doc = elem.documentElement;
+
+ // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+ // so we can't use max, as it'll choose the incorrect offset[Width/Height]
+ // instead we use the correct client[Width/Height]
+ // support:IE6
+ if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+ return doc[ clientProp ];
+ }
+
+ return Math.max(
+ elem.body[ scrollProp ], doc[ scrollProp ],
+ elem.body[ offsetProp ], doc[ offsetProp ]
+ );
+ }
+
+ // Get width or height on the element
+ if ( value === undefined ) {
+ orig = jQuery.css( elem, type );
+ ret = parseFloat( orig );
+ return jQuery.isNumeric( ret ) ? ret : orig;
+ }
+
+ // Set the width or height on the element
+ jQuery( elem ).css( type, value );
+ }, type, value, arguments.length, null );
+ };
+});
+
+
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+
+
+})( window );
\ No newline at end of file
--- /dev/null
+/*
+* jQuery Mobile Framework 1.1.1 1981b3f5ec22675ae47df8f0bdf9622e7780e90e
+* http://jquerymobile.com
+*
+* Copyright 2012 jQuery Foundation and other contributors
+* Dual licensed under the MIT or GPL Version 2 licenses.
+* http://jquery.org/license
+*
+*/
+(function ( root, doc, factory ) {
+ if ( typeof define === "function" && define.amd ) {
+ // AMD. Register as an anonymous module.
+ define( [ "jquery" ], function ( $ ) {
+ factory( $, root, doc );
+ return $.mobile;
+ });
+ } else {
+ // Browser globals
+ factory( root.jQuery, root, doc );
+ }
+}( this, document, function ( jQuery, window, document, undefined ) {
+
+
+// This plugin is an experiment for abstracting away the touch and mouse
+// events so that developers don't have to worry about which method of input
+// the device their document is loaded on supports.
+//
+// The idea here is to allow the developer to register listeners for the
+// basic mouse events, such as mousedown, mousemove, mouseup, and click,
+// and the plugin will take care of registering the correct listeners
+// behind the scenes to invoke the listener at the fastest possible time
+// for that device, while still retaining the order of event firing in
+// the traditional mouse environment, should multiple handlers be registered
+// on the same element for different events.
+//
+// The current version exposes the following virtual events to jQuery bind methods:
+// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
+
+(function( $, window, document, undefined ) {
+
+var dataPropertyName = "virtualMouseBindings",
+ touchTargetPropertyName = "virtualTouchID",
+ virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
+ touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
+ mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [],
+ mouseEventProps = $.event.props.concat( mouseHookProps ),
+ activeDocHandlers = {},
+ resetTimerID = 0,
+ startX = 0,
+ startY = 0,
+ didScroll = false,
+ clickBlockList = [],
+ blockMouseTriggers = false,
+ blockTouchTriggers = false,
+ eventCaptureSupported = "addEventListener" in document,
+ $document = $( document ),
+ nextTouchID = 1,
+ lastTouchID = 0;
+
+$.vmouse = {
+ moveDistanceThreshold: 10,
+ clickDistanceThreshold: 10,
+ resetTimerDuration: 1500
+};
+
+function getNativeEvent( event ) {
+
+ while ( event && typeof event.originalEvent !== "undefined" ) {
+ event = event.originalEvent;
+ }
+ return event;
+}
+
+function createVirtualEvent( event, eventType ) {
+
+ var t = event.type,
+ oe, props, ne, prop, ct, touch, i, j;
+
+ event = $.Event(event);
+ event.type = eventType;
+
+ oe = event.originalEvent;
+ props = $.event.props;
+
+ // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
+ // https://github.com/jquery/jquery-mobile/issues/3280
+ if ( t.search( /^(mouse|click)/ ) > -1 ) {
+ props = mouseEventProps;
+ }
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ if ( oe ) {
+ for ( i = props.length, prop; i; ) {
+ prop = props[ --i ];
+ event[ prop ] = oe[ prop ];
+ }
+ }
+
+ // make sure that if the mouse and click virtual events are generated
+ // without a .which one is defined
+ if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){
+ event.which = 1;
+ }
+
+ if ( t.search(/^touch/) !== -1 ) {
+ ne = getNativeEvent( oe );
+ t = ne.touches;
+ ct = ne.changedTouches;
+ touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );
+
+ if ( touch ) {
+ for ( j = 0, len = touchEventProps.length; j < len; j++){
+ prop = touchEventProps[ j ];
+ event[ prop ] = touch[ prop ];
+ }
+ }
+ }
+
+ return event;
+}
+
+function getVirtualBindingFlags( element ) {
+
+ var flags = {},
+ b, k;
+
+ while ( element ) {
+
+ b = $.data( element, dataPropertyName );
+
+ for ( k in b ) {
+ if ( b[ k ] ) {
+ flags[ k ] = flags.hasVirtualBinding = true;
+ }
+ }
+ element = element.parentNode;
+ }
+ return flags;
+}
+
+function getClosestElementWithVirtualBinding( element, eventType ) {
+ var b;
+ while ( element ) {
+
+ b = $.data( element, dataPropertyName );
+
+ if ( b && ( !eventType || b[ eventType ] ) ) {
+ return element;
+ }
+ element = element.parentNode;
+ }
+ return null;
+}
+
+function enableTouchBindings() {
+ blockTouchTriggers = false;
+}
+
+function disableTouchBindings() {
+ blockTouchTriggers = true;
+}
+
+function enableMouseBindings() {
+ lastTouchID = 0;
+ clickBlockList.length = 0;
+ blockMouseTriggers = false;
+
+ // When mouse bindings are enabled, our
+ // touch bindings are disabled.
+ disableTouchBindings();
+}
+
+function disableMouseBindings() {
+ // When mouse bindings are disabled, our
+ // touch bindings are enabled.
+ enableTouchBindings();
+}
+
+function startResetTimer() {
+ clearResetTimer();
+ resetTimerID = setTimeout(function(){
+ resetTimerID = 0;
+ enableMouseBindings();
+ }, $.vmouse.resetTimerDuration );
+}
+
+function clearResetTimer() {
+ if ( resetTimerID ){
+ clearTimeout( resetTimerID );
+ resetTimerID = 0;
+ }
+}
+
+function triggerVirtualEvent( eventType, event, flags ) {
+ var ve;
+
+ if ( ( flags && flags[ eventType ] ) ||
+ ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
+
+ ve = createVirtualEvent( event, eventType );
+
+ $( event.target).trigger( ve );
+ }
+
+ return ve;
+}
+
+function mouseEventCallback( event ) {
+ var touchID = $.data(event.target, touchTargetPropertyName);
+
+ if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
+ var ve = triggerVirtualEvent( "v" + event.type, event );
+ if ( ve ) {
+ if ( ve.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ if ( ve.isPropagationStopped() ) {
+ event.stopPropagation();
+ }
+ if ( ve.isImmediatePropagationStopped() ) {
+ event.stopImmediatePropagation();
+ }
+ }
+ }
+}
+
+function handleTouchStart( event ) {
+
+ var touches = getNativeEvent( event ).touches,
+ target, flags;
+
+ if ( touches && touches.length === 1 ) {
+
+ target = event.target;
+ flags = getVirtualBindingFlags( target );
+
+ if ( flags.hasVirtualBinding ) {
+
+ lastTouchID = nextTouchID++;
+ $.data( target, touchTargetPropertyName, lastTouchID );
+
+ clearResetTimer();
+
+ disableMouseBindings();
+ didScroll = false;
+
+ var t = getNativeEvent( event ).touches[ 0 ];
+ startX = t.pageX;
+ startY = t.pageY;
+
+ triggerVirtualEvent( "vmouseover", event, flags );
+ triggerVirtualEvent( "vmousedown", event, flags );
+ }
+ }
+}
+
+function handleScroll( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ if ( !didScroll ) {
+ triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
+ }
+
+ didScroll = true;
+ startResetTimer();
+}
+
+function handleTouchMove( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ var t = getNativeEvent( event ).touches[ 0 ],
+ didCancel = didScroll,
+ moveThreshold = $.vmouse.moveDistanceThreshold;
+ didScroll = didScroll ||
+ ( Math.abs(t.pageX - startX) > moveThreshold ||
+ Math.abs(t.pageY - startY) > moveThreshold ),
+ flags = getVirtualBindingFlags( event.target );
+
+ if ( didScroll && !didCancel ) {
+ triggerVirtualEvent( "vmousecancel", event, flags );
+ }
+
+ triggerVirtualEvent( "vmousemove", event, flags );
+ startResetTimer();
+}
+
+function handleTouchEnd( event ) {
+ if ( blockTouchTriggers ) {
+ return;
+ }
+
+ disableTouchBindings();
+
+ var flags = getVirtualBindingFlags( event.target ),
+ t;
+ triggerVirtualEvent( "vmouseup", event, flags );
+
+ if ( !didScroll ) {
+ var ve = triggerVirtualEvent( "vclick", event, flags );
+ if ( ve && ve.isDefaultPrevented() ) {
+ // The target of the mouse events that follow the touchend
+ // event don't necessarily match the target used during the
+ // touch. This means we need to rely on coordinates for blocking
+ // any click that is generated.
+ t = getNativeEvent( event ).changedTouches[ 0 ];
+ clickBlockList.push({
+ touchID: lastTouchID,
+ x: t.clientX,
+ y: t.clientY
+ });
+
+ // Prevent any mouse events that follow from triggering
+ // virtual event notifications.
+ blockMouseTriggers = true;
+ }
+ }
+ triggerVirtualEvent( "vmouseout", event, flags);
+ didScroll = false;
+
+ startResetTimer();
+}
+
+function hasVirtualBindings( ele ) {
+ var bindings = $.data( ele, dataPropertyName ),
+ k;
+
+ if ( bindings ) {
+ for ( k in bindings ) {
+ if ( bindings[ k ] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+function dummyMouseHandler(){}
+
+function getSpecialEventObject( eventType ) {
+ var realType = eventType.substr( 1 );
+
+ return {
+ setup: function( data, namespace ) {
+ // If this is the first virtual mouse binding for this element,
+ // add a bindings object to its data.
+
+ if ( !hasVirtualBindings( this ) ) {
+ $.data( this, dataPropertyName, {});
+ }
+
+ // If setup is called, we know it is the first binding for this
+ // eventType, so initialize the count for the eventType to zero.
+ var bindings = $.data( this, dataPropertyName );
+ bindings[ eventType ] = true;
+
+ // If this is the first virtual mouse event for this type,
+ // register a global handler on the document.
+
+ activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
+
+ if ( activeDocHandlers[ eventType ] === 1 ) {
+ $document.bind( realType, mouseEventCallback );
+ }
+
+ // Some browsers, like Opera Mini, won't dispatch mouse/click events
+ // for elements unless they actually have handlers registered on them.
+ // To get around this, we register dummy handlers on the elements.
+
+ $( this ).bind( realType, dummyMouseHandler );
+
+ // For now, if event capture is not supported, we rely on mouse handlers.
+ if ( eventCaptureSupported ) {
+ // If this is the first virtual mouse binding for the document,
+ // register our touchstart handler on the document.
+
+ activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
+
+ if (activeDocHandlers[ "touchstart" ] === 1) {
+ $document.bind( "touchstart", handleTouchStart )
+ .bind( "touchend", handleTouchEnd )
+
+ // On touch platforms, touching the screen and then dragging your finger
+ // causes the window content to scroll after some distance threshold is
+ // exceeded. On these platforms, a scroll prevents a click event from being
+ // dispatched, and on some platforms, even the touchend is suppressed. To
+ // mimic the suppression of the click event, we need to watch for a scroll
+ // event. Unfortunately, some platforms like iOS don't dispatch scroll
+ // events until *AFTER* the user lifts their finger (touchend). This means
+ // we need to watch both scroll and touchmove events to figure out whether
+ // or not a scroll happenens before the touchend event is fired.
+
+ .bind( "touchmove", handleTouchMove )
+ .bind( "scroll", handleScroll );
+ }
+ }
+ },
+
+ teardown: function( data, namespace ) {
+ // If this is the last virtual binding for this eventType,
+ // remove its global handler from the document.
+
+ --activeDocHandlers[ eventType ];
+
+ if ( !activeDocHandlers[ eventType ] ) {
+ $document.unbind( realType, mouseEventCallback );
+ }
+
+ if ( eventCaptureSupported ) {
+ // If this is the last virtual mouse binding in existence,
+ // remove our document touchstart listener.
+
+ --activeDocHandlers[ "touchstart" ];
+
+ if ( !activeDocHandlers[ "touchstart" ] ) {
+ $document.unbind( "touchstart", handleTouchStart )
+ .unbind( "touchmove", handleTouchMove )
+ .unbind( "touchend", handleTouchEnd )
+ .unbind( "scroll", handleScroll );
+ }
+ }
+
+ var $this = $( this ),
+ bindings = $.data( this, dataPropertyName );
+
+ // teardown may be called when an element was
+ // removed from the DOM. If this is the case,
+ // jQuery core may have already stripped the element
+ // of any data bindings so we need to check it before
+ // using it.
+ if ( bindings ) {
+ bindings[ eventType ] = false;
+ }
+
+ // Unregister the dummy event handler.
+
+ $this.unbind( realType, dummyMouseHandler );
+
+ // If this is the last virtual mouse binding on the
+ // element, remove the binding data from the element.
+
+ if ( !hasVirtualBindings( this ) ) {
+ $this.removeData( dataPropertyName );
+ }
+ }
+ };
+}
+
+// Expose our custom events to the jQuery bind/unbind mechanism.
+
+for ( var i = 0; i < virtualEventNames.length; i++ ){
+ $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
+}
+
+// Add a capture click handler to block clicks.
+// Note that we require event capture support for this so if the device
+// doesn't support it, we punt for now and rely solely on mouse events.
+if ( eventCaptureSupported ) {
+ document.addEventListener( "click", function( e ){
+ var cnt = clickBlockList.length,
+ target = e.target,
+ x, y, ele, i, o, touchID;
+
+ if ( cnt ) {
+ x = e.clientX;
+ y = e.clientY;
+ threshold = $.vmouse.clickDistanceThreshold;
+
+ // The idea here is to run through the clickBlockList to see if
+ // the current click event is in the proximity of one of our
+ // vclick events that had preventDefault() called on it. If we find
+ // one, then we block the click.
+ //
+ // Why do we have to rely on proximity?
+ //
+ // Because the target of the touch event that triggered the vclick
+ // can be different from the target of the click event synthesized
+ // by the browser. The target of a mouse/click event that is syntehsized
+ // from a touch event seems to be implementation specific. For example,
+ // some browsers will fire mouse/click events for a link that is near
+ // a touch event, even though the target of the touchstart/touchend event
+ // says the user touched outside the link. Also, it seems that with most
+ // browsers, the target of the mouse/click event is not calculated until the
+ // time it is dispatched, so if you replace an element that you touched
+ // with another element, the target of the mouse/click will be the new
+ // element underneath that point.
+ //
+ // Aside from proximity, we also check to see if the target and any
+ // of its ancestors were the ones that blocked a click. This is necessary
+ // because of the strange mouse/click target calculation done in the
+ // Android 2.1 browser, where if you click on an element, and there is a
+ // mouse/click handler on one of its ancestors, the target will be the
+ // innermost child of the touched element, even if that child is no where
+ // near the point of touch.
+
+ ele = target;
+
+ while ( ele ) {
+ for ( i = 0; i < cnt; i++ ) {
+ o = clickBlockList[ i ];
+ touchID = 0;
+
+ if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
+ $.data( ele, touchTargetPropertyName ) === o.touchID ) {
+ // XXX: We may want to consider removing matches from the block list
+ // instead of waiting for the reset timer to fire.
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ }
+ ele = ele.parentNode;
+ }
+ }
+ }, true);
+}
+})( jQuery, window, document );
+
+
+
+// Script: jQuery hashchange event
+//
+// *Version: 1.3, Last updated: 7/21/2010*
+//
+// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
+// GitHub - http://github.com/cowboy/jquery-hashchange/
+// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
+// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
+//
+// About: License
+//
+// Copyright (c) 2010 "Cowboy" Ben Alman,
+// Dual licensed under the MIT and GPL licenses.
+// http://benalman.com/about/license/
+//
+// About: Examples
+//
+// These working examples, complete with fully commented code, illustrate a few
+// ways in which this plugin can be used.
+//
+// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
+// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
+//
+// About: Support and Testing
+//
+// Information about what version or versions of jQuery this plugin has been
+// tested with, what browsers it has been tested in, and where the unit tests
+// reside (so you can test it yourself).
+//
+// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
+// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
+// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
+// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
+//
+// About: Known issues
+//
+// While this jQuery hashchange event implementation is quite stable and
+// robust, there are a few unfortunate browser bugs surrounding expected
+// hashchange event-based behaviors, independent of any JavaScript
+// window.onhashchange abstraction. See the following examples for more
+// information:
+//
+// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
+// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
+// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
+// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
+//
+// Also note that should a browser natively support the window.onhashchange
+// event, but not report that it does, the fallback polling loop will be used.
+//
+// About: Release History
+//
+// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
+// "removable" for mobile-only development. Added IE6/7 document.title
+// support. Attempted to make Iframe as hidden as possible by using
+// techniques from http://www.paciellogroup.com/blog/?p=604. Added
+// support for the "shortcut" format $(window).hashchange( fn ) and
+// $(window).hashchange() like jQuery provides for built-in events.
+// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
+// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
+// and <jQuery.fn.hashchange.src> properties plus document-domain.html
+// file to address access denied issues when setting document.domain in
+// IE6/7.
+// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
+// from a page on another domain would cause an error in Safari 4. Also,
+// IE6/7 Iframe is now inserted after the body (this actually works),
+// which prevents the page from scrolling when the event is first bound.
+// Event can also now be bound before DOM ready, but it won't be usable
+// before then in IE6/7.
+// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
+// where browser version is incorrectly reported as 8.0, despite
+// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
+// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
+// window.onhashchange functionality into a separate plugin for users
+// who want just the basic event & back button support, without all the
+// extra awesomeness that BBQ provides. This plugin will be included as
+// part of jQuery BBQ, but also be available separately.
+
+(function($,window,undefined){
+ // Reused string.
+ var str_hashchange = 'hashchange',
+
+ // Method / object references.
+ doc = document,
+ fake_onhashchange,
+ special = $.event.special,
+
+ // Does the browser support window.onhashchange? Note that IE8 running in
+ // IE7 compatibility mode reports true for 'onhashchange' in window, even
+ // though the event isn't supported, so also test document.documentMode.
+ doc_mode = doc.documentMode,
+ supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
+
+ // Get location.hash (or what you'd expect location.hash to be) sans any
+ // leading #. Thanks for making this necessary, Firefox!
+ function get_fragment( url ) {
+ url = url || location.href;
+ return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
+ };
+
+ // Method: jQuery.fn.hashchange
+ //
+ // Bind a handler to the window.onhashchange event or trigger all bound
+ // window.onhashchange event handlers. This behavior is consistent with
+ // jQuery's built-in event handlers.
+ //
+ // Usage:
+ //
+ // > jQuery(window).hashchange( [ handler ] );
+ //
+ // Arguments:
+ //
+ // handler - (Function) Optional handler to be bound to the hashchange
+ // event. This is a "shortcut" for the more verbose form:
+ // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
+ // all bound window.onhashchange event handlers will be triggered. This
+ // is a shortcut for the more verbose
+ // jQuery(window).trigger( 'hashchange' ). These forms are described in
+ // the <hashchange event> section.
+ //
+ // Returns:
+ //
+ // (jQuery) The initial jQuery collection of elements.
+
+ // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
+ // $(elem).hashchange() for triggering, like jQuery does for built-in events.
+ $.fn[ str_hashchange ] = function( fn ) {
+ return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
+ };
+
+ // Property: jQuery.fn.hashchange.delay
+ //
+ // The numeric interval (in milliseconds) at which the <hashchange event>
+ // polling loop executes. Defaults to 50.
+
+ // Property: jQuery.fn.hashchange.domain
+ //
+ // If you're setting document.domain in your JavaScript, and you want hash
+ // history to work in IE6/7, not only must this property be set, but you must
+ // also set document.domain BEFORE jQuery is loaded into the page. This
+ // property is only applicable if you are supporting IE6/7 (or IE8 operating
+ // in "IE7 compatibility" mode).
+ //
+ // In addition, the <jQuery.fn.hashchange.src> property must be set to the
+ // path of the included "document-domain.html" file, which can be renamed or
+ // modified if necessary (note that the document.domain specified must be the
+ // same in both your main JavaScript as well as in this file).
+ //
+ // Usage:
+ //
+ // jQuery.fn.hashchange.domain = document.domain;
+
+ // Property: jQuery.fn.hashchange.src
+ //
+ // If, for some reason, you need to specify an Iframe src file (for example,
+ // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
+ // do so using this property. Note that when using this property, history
+ // won't be recorded in IE6/7 until the Iframe src file loads. This property
+ // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
+ // compatibility" mode).
+ //
+ // Usage:
+ //
+ // jQuery.fn.hashchange.src = 'path/to/file.html';
+
+ $.fn[ str_hashchange ].delay = 50;
+ /*
+ $.fn[ str_hashchange ].domain = null;
+ $.fn[ str_hashchange ].src = null;
+ */
+
+ // Event: hashchange event
+ //
+ // Fired when location.hash changes. In browsers that support it, the native
+ // HTML5 window.onhashchange event is used, otherwise a polling loop is
+ // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
+ // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
+ // compatibility" mode), a hidden Iframe is created to allow the back button
+ // and hash-based history to work.
+ //
+ // Usage as described in <jQuery.fn.hashchange>:
+ //
+ // > // Bind an event handler.
+ // > jQuery(window).hashchange( function(e) {
+ // > var hash = location.hash;
+ // > ...
+ // > });
+ // >
+ // > // Manually trigger the event handler.
+ // > jQuery(window).hashchange();
+ //
+ // A more verbose usage that allows for event namespacing:
+ //
+ // > // Bind an event handler.
+ // > jQuery(window).bind( 'hashchange', function(e) {
+ // > var hash = location.hash;
+ // > ...
+ // > });
+ // >
+ // > // Manually trigger the event handler.
+ // > jQuery(window).trigger( 'hashchange' );
+ //
+ // Additional Notes:
+ //
+ // * The polling loop and Iframe are not created until at least one handler
+ // is actually bound to the 'hashchange' event.
+ // * If you need the bound handler(s) to execute immediately, in cases where
+ // a location.hash exists on page load, via bookmark or page refresh for
+ // example, use jQuery(window).hashchange() or the more verbose
+ // jQuery(window).trigger( 'hashchange' ).
+ // * The event can be bound before DOM ready, but since it won't be usable
+ // before then in IE6/7 (due to the necessary Iframe), recommended usage is
+ // to bind it inside a DOM ready handler.
+
+ // Override existing $.event.special.hashchange methods (allowing this plugin
+ // to be defined after jQuery BBQ in BBQ's source code).
+ special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
+
+ // Called only when the first 'hashchange' event is bound to window.
+ setup: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to create our own. And we don't want to call this
+ // until the user binds to the event, just in case they never do, since it
+ // will create a polling loop and possibly even a hidden Iframe.
+ $( fake_onhashchange.start );
+ },
+
+ // Called only when the last 'hashchange' event is unbound from window.
+ teardown: function() {
+ // If window.onhashchange is supported natively, there's nothing to do..
+ if ( supports_onhashchange ) { return false; }
+
+ // Otherwise, we need to stop ours (if possible).
+ $( fake_onhashchange.stop );
+ }
+
+ });
+
+ // fake_onhashchange does all the work of triggering the window.onhashchange
+ // event for browsers that don't natively support it, including creating a
+ // polling loop to watch for hash changes and in IE 6/7 creating a hidden
+ // Iframe to enable back and forward.
+ fake_onhashchange = (function(){
+ var self = {},
+ timeout_id,
+
+ // Remember the initial hash so it doesn't get triggered immediately.
+ last_hash = get_fragment(),
+
+ fn_retval = function(val){ return val; },
+ history_set = fn_retval,
+ history_get = fn_retval;
+
+ // Start the polling loop.
+ self.start = function() {
+ timeout_id || poll();
+ };
+
+ // Stop the polling loop.
+ self.stop = function() {
+ timeout_id && clearTimeout( timeout_id );
+ timeout_id = undefined;
+ };
+
+ // This polling loop checks every $.fn.hashchange.delay milliseconds to see
+ // if location.hash has changed, and triggers the 'hashchange' event on
+ // window when necessary.
+ function poll() {
+ var hash = get_fragment(),
+ history_hash = history_get( last_hash );
+
+ if ( hash !== last_hash ) {
+ history_set( last_hash = hash, history_hash );
+
+ $(window).trigger( str_hashchange );
+
+ } else if ( history_hash !== last_hash ) {
+ location.href = location.href.replace( /#.*/, '' ) + history_hash;
+ }
+
+ timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
+ };
+
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
+ // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ $.browser.msie && !supports_onhashchange && (function(){
+ // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
+ // when running in "IE7 compatibility" mode.
+
+ var iframe,
+ iframe_src;
+
+ // When the event is bound and polling starts in IE 6/7, create a hidden
+ // Iframe for history handling.
+ self.start = function(){
+ if ( !iframe ) {
+ iframe_src = $.fn[ str_hashchange ].src;
+ iframe_src = iframe_src && iframe_src + get_fragment();
+
+ // Create hidden Iframe. Attempt to make Iframe as hidden as possible
+ // by using techniques from http://www.paciellogroup.com/blog/?p=604.
+ iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
+
+ // When Iframe has completely loaded, initialize the history and
+ // start polling.
+ .one( 'load', function(){
+ iframe_src || history_set( get_fragment() );
+ poll();
+ })
+
+ // Load Iframe src if specified, otherwise nothing.
+ .attr( 'src', iframe_src || 'javascript:0' )
+
+ // Append Iframe after the end of the body to prevent unnecessary
+ // initial page scrolling (yes, this works).
+ .insertAfter( 'body' )[0].contentWindow;
+
+ // Whenever `document.title` changes, update the Iframe's title to
+ // prettify the back/next history menu entries. Since IE sometimes
+ // errors with "Unspecified error" the very first time this is set
+ // (yes, very useful) wrap this with a try/catch block.
+ doc.onpropertychange = function(){
+ try {
+ if ( event.propertyName === 'title' ) {
+ iframe.document.title = doc.title;
+ }
+ } catch(e) {}
+ };
+
+ }
+ };
+
+ // Override the "stop" method since an IE6/7 Iframe was created. Even
+ // if there are no longer any bound event handlers, the polling loop
+ // is still necessary for back/next to work at all!
+ self.stop = fn_retval;
+
+ // Get history by looking at the hidden Iframe's location.hash.
+ history_get = function() {
+ return get_fragment( iframe.location.href );
+ };
+
+ // Set a new history item by opening and then closing the Iframe
+ // document, *then* setting its location.hash. If document.domain has
+ // been set, update that as well.
+ history_set = function( hash, history_hash ) {
+ var iframe_doc = iframe.document,
+ domain = $.fn[ str_hashchange ].domain;
+
+ if ( hash !== history_hash ) {
+ // Update Iframe with any initial `document.title` that might be set.
+ iframe_doc.title = doc.title;
+
+ // Opening the Iframe's document after it has been closed is what
+ // actually adds a history entry.
+ iframe_doc.open();
+
+ // Set document.domain for the Iframe document as well, if necessary.
+ domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
+
+ iframe_doc.close();
+
+ // Update the Iframe's hash, for great justice.
+ iframe.location.hash = hash;
+ }
+ };
+
+ })();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ return self;
+ })();
+
+})(jQuery,this);
+
+/*!
+ * jQuery UI Widget @VERSION
+ *
+ * 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/Widget
+ */
+
+(function( $, undefined ) {
+
+// jQuery 1.4+
+if ( $.cleanData ) {
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+ _cleanData( elems );
+ };
+} else {
+ var _remove = $.fn.remove;
+ $.fn.remove = function( selector, keepData ) {
+ return this.each(function() {
+ if ( !keepData ) {
+ if ( !selector || $.filter( selector, [ this ] ).length ) {
+ $( "*", this ).add( [ this ] ).each(function() {
+ $( this ).triggerHandler( "remove" );
+ });
+ }
+ }
+ return _remove.call( $(this), selector, keepData );
+ });
+ };
+}
+
+$.widget = function( name, base, prototype ) {
+ var namespace = name.split( "." )[ 0 ],
+ fullName;
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName ] = function( elem ) {
+ return !!$.data( elem, name );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ var basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+// $.each( basePrototype, function( key, val ) {
+// if ( $.isPlainObject(val) ) {
+// basePrototype[ key ] = $.extend( {}, val );
+// }
+// });
+ basePrototype.options = $.extend( true, {}, basePrototype.options );
+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+ namespace: namespace,
+ widgetName: name,
+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
+ widgetBaseClass: fullName
+ }, prototype );
+
+ $.widget.bridge( name, $[ namespace ][ name ] );
+};
+
+$.widget.bridge = function( name, object ) {
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = Array.prototype.slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.extend.apply( null, [ true, options ].concat(args) ) :
+ options;
+
+ // prevent calls to internal methods
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+ return returnValue;
+ }
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( !instance ) {
+ throw "cannot call methods on " + name + " prior to initialization; " +
+ "attempted to call method '" + options + "'";
+ }
+ if ( !$.isFunction( instance[options] ) ) {
+ throw "no such method '" + options + "' for " + name + " widget instance";
+ }
+ var methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, name, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+};
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ options: {
+ disabled: false
+ },
+ _createWidget: function( options, element ) {
+ // $.widget.bridge stores the plugin instance, but we do it anyway
+ // so that it's stored even before the _create function runs
+ $.data( element, this.widgetName, this );
+ this.element = $( element );
+ this.options = $.extend( true, {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ var self = this;
+ this.element.bind( "remove." + this.widgetName, function() {
+ self.destroy();
+ });
+
+ this._create();
+ this._trigger( "create" );
+ this._init();
+ },
+ _getCreateOptions: function() {
+ var options = {};
+ if ( $.metadata ) {
+ options = $.metadata.get( element )[ this.widgetName ];
+ }
+ return options;
+ },
+ _create: function() {},
+ _init: function() {},
+
+ destroy: function() {
+ this.element
+ .unbind( "." + this.widgetName )
+ .removeData( this.widgetName );
+ this.widget()
+ .unbind( "." + this.widgetName )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetBaseClass + "-disabled " +
+ "ui-state-disabled" );
+ },
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.extend( {}, this.options );
+ }
+
+ if (typeof key === "string" ) {
+ if ( value === undefined ) {
+ return this.options[ key ];
+ }
+ options = {};
+ options[ key ] = value;
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var self = this;
+ $.each( options, function( key, value ) {
+ self._setOption( key, value );
+ });
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ [ value ? "addClass" : "removeClass"](
+ this.widgetBaseClass + "-disabled" + " " +
+ "ui-state-disabled" )
+ .attr( "aria-disabled", value );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _trigger: function( type, event, data ) {
+ var callback = this.options[ type ];
+
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ data = data || {};
+
+ // copy original event properties over to the new event
+ // this would happen if we could call $.event.fix instead of $.Event
+ // but we don't have a way to force an event to be fixed multiple times
+ if ( event.originalEvent ) {
+ for ( var i = $.event.props.length, prop; i; ) {
+ prop = $.event.props[ --i ];
+ event[ prop ] = event.originalEvent[ prop ];
+ }
+ }
+
+ this.element.trigger( event, data );
+
+ return !( $.isFunction(callback) &&
+ callback.call( this.element[0], event, data ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.widget", {
+ // decorate the parent _createWidget to trigger `widgetinit` for users
+ // who wish to do post post `widgetcreate` alterations/additions
+ //
+ // TODO create a pull request for jquery ui to trigger this event
+ // in the original _createWidget
+ _createWidget: function() {
+ $.Widget.prototype._createWidget.apply( this, arguments );
+ this._trigger( 'init' );
+ },
+
+ _getCreateOptions: function() {
+
+ var elem = this.element,
+ options = {};
+
+ $.each( this.options, function( option ) {
+
+ var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
+ return "-" + c.toLowerCase();
+ })
+ );
+
+ if ( value !== undefined ) {
+ options[ option ] = value;
+ }
+ });
+
+ return options;
+ },
+
+ enhanceWithin: function( target, useKeepNative ) {
+ this.enhance( $( this.options.initSelector, $( target )), useKeepNative );
+ },
+
+ enhance: function( targets, useKeepNative ) {
+ var page, keepNative, $widgetElements = $( targets ), self = this;
+
+ // if ignoreContentEnabled is set to true the framework should
+ // only enhance the selected elements when they do NOT have a
+ // parent with the data-namespace-ignore attribute
+ $widgetElements = $.mobile.enhanceable( $widgetElements );
+
+ if ( useKeepNative && $widgetElements.length ) {
+ // TODO remove dependency on the page widget for the keepNative.
+ // Currently the keepNative value is defined on the page prototype so
+ // the method is as well
+ page = $.mobile.closestPageData( $widgetElements );
+ keepNative = (page && page.keepNativeSelector()) || "";
+
+ $widgetElements = $widgetElements.not( keepNative );
+ }
+
+ $widgetElements[ this.widgetName ]();
+ },
+
+ raise: function( msg ) {
+ throw "Widget [" + this.widgetName + "]: " + msg;
+ }
+});
+
+})( jQuery );
+
+(function( $, window, undefined ) {
+
+ var nsNormalizeDict = {};
+
+ // jQuery.mobile configurable options
+ $.mobile = $.extend( {}, {
+
+ // Version of the jQuery Mobile Framework
+ version: "1.1.1",
+
+ // Namespace used framework-wide for data-attrs. Default is no namespace
+ ns: "",
+
+ // Define the url parameter used for referencing widget-generated sub-pages.
+ // Translates to to example.html&ui-page=subpageIdentifier
+ // hash segment before &ui-page= is used to make Ajax request
+ subPageUrlKey: "ui-page",
+
+ // Class assigned to page currently in view, and during transitions
+ activePageClass: "ui-page-active",
+
+ // Class used for "active" button state, from CSS framework
+ activeBtnClass: "ui-btn-active",
+
+ // Class used for "focus" form element state, from CSS framework
+ focusClass: "ui-focus",
+
+ // Automatically handle clicks and form submissions through Ajax, when same-domain
+ ajaxEnabled: true,
+
+ // Automatically load and show pages based on location.hash
+ hashListeningEnabled: true,
+
+ // disable to prevent jquery from bothering with links
+ linkBindingEnabled: true,
+
+ // Set default page transition - 'none' for no transitions
+ defaultPageTransition: "fade",
+
+ // Set maximum window width for transitions to apply - 'false' for no limit
+ maxTransitionWidth: false,
+
+ // Minimum scroll distance that will be remembered when returning to a page
+ minScrollBack: 250,
+
+ // DEPRECATED: the following property is no longer in use, but defined until 2.0 to prevent conflicts
+ touchOverflowEnabled: false,
+
+ // Set default dialog transition - 'none' for no transitions
+ defaultDialogTransition: "pop",
+
+ // Show loading message during Ajax requests
+ // if false, message will not appear, but loading classes will still be toggled on html el
+ loadingMessage: "loading",
+
+ // Error response message - appears when an Ajax page request fails
+ pageLoadErrorMessage: "Error Loading Page",
+
+ // Should the text be visble in the loading message?
+ loadingMessageTextVisible: false,
+
+ // When the text is visible, what theme does the loading box use?
+ loadingMessageTheme: "a",
+
+ // For error messages, which theme does the box uses?
+ pageLoadErrorMessageTheme: "e",
+
+ //automatically initialize the DOM when it's ready
+ autoInitializePage: true,
+
+ pushStateEnabled: true,
+
+ // allows users to opt in to ignoring content by marking a parent element as
+ // data-ignored
+ ignoreContentEnabled: false,
+
+ // turn of binding to the native orientationchange due to android orientation behavior
+ orientationChangeEnabled: true,
+
+ buttonMarkup: {
+ hoverDelay: 200
+ },
+
+ // TODO might be useful upstream in jquery itself ?
+ keyCode: {
+ ALT: 18,
+ BACKSPACE: 8,
+ CAPS_LOCK: 20,
+ COMMA: 188,
+ COMMAND: 91,
+ COMMAND_LEFT: 91, // COMMAND
+ COMMAND_RIGHT: 93,
+ CONTROL: 17,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ INSERT: 45,
+ LEFT: 37,
+ MENU: 93, // COMMAND_RIGHT
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SHIFT: 16,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38,
+ WINDOWS: 91 // COMMAND
+ },
+
+ // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
+ silentScroll: function( ypos ) {
+ if ( $.type( ypos ) !== "number" ) {
+ ypos = $.mobile.defaultHomeScroll;
+ }
+
+ // prevent scrollstart and scrollstop events
+ $.event.special.scrollstart.enabled = false;
+
+ setTimeout(function() {
+ window.scrollTo( 0, ypos );
+ $( document ).trigger( "silentscroll", { x: 0, y: ypos });
+ }, 20 );
+
+ setTimeout(function() {
+ $.event.special.scrollstart.enabled = true;
+ }, 150 );
+ },
+
+ // Expose our cache for testing purposes.
+ nsNormalizeDict: nsNormalizeDict,
+
+ // Take a data attribute property, prepend the namespace
+ // and then camel case the attribute string. Add the result
+ // to our nsNormalizeDict so we don't have to do this again.
+ nsNormalize: function( prop ) {
+ if ( !prop ) {
+ return;
+ }
+
+ return nsNormalizeDict[ prop ] || ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) );
+ },
+
+ // Find the closest parent with a theme class on it. Note that
+ // we are not using $.fn.closest() on purpose here because this
+ // method gets called quite a bit and we need it to be as fast
+ // as possible.
+ getInheritedTheme: function( el, defaultTheme ) {
+ var e = el[ 0 ],
+ ltr = "",
+ re = /ui-(bar|body|overlay)-([a-z])\b/,
+ c, m;
+
+ while ( e ) {
+ c = e.className || "";
+ if ( c && ( m = re.exec( c ) ) && ( ltr = m[ 2 ] ) ) {
+ // We found a parent with a theme class
+ // on it so bail from this loop.
+ break;
+ }
+
+ e = e.parentNode;
+ }
+
+ // Return the theme letter we found, if none, return the
+ // specified default.
+
+ return ltr || defaultTheme || "a";
+ },
+
+ // TODO the following $ and $.fn extensions can/probably should be moved into jquery.mobile.core.helpers
+ //
+ // Find the closest javascript page element to gather settings data jsperf test
+ // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit
+ // possibly naive, but it shows that the parsing overhead for *just* the page selector vs
+ // the page and dialog selector is negligable. This could probably be speed up by
+ // doing a similar parent node traversal to the one found in the inherited theme code above
+ closestPageData: function( $target ) {
+ return $target
+ .closest(':jqmData(role="page"), :jqmData(role="dialog")')
+ .data("page");
+ },
+
+ enhanceable: function( $set ) {
+ return this.haveParents( $set, "enhance" );
+ },
+
+ hijackable: function( $set ) {
+ return this.haveParents( $set, "ajax" );
+ },
+
+ haveParents: function( $set, attr ) {
+ if( !$.mobile.ignoreContentEnabled ){
+ return $set;
+ }
+
+ var count = $set.length,
+ $newSet = $(),
+ e, $element, excluded;
+
+ for ( var i = 0; i < count; i++ ) {
+ $element = $set.eq( i );
+ excluded = false;
+ e = $set[ i ];
+
+ while ( e ) {
+ var c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : "";
+
+ if ( c === "false" ) {
+ excluded = true;
+ break;
+ }
+
+ e = e.parentNode;
+ }
+
+ if ( !excluded ) {
+ $newSet = $newSet.add( $element );
+ }
+ }
+
+ return $newSet;
+ },
+
+ getScreenHeight: function(){
+ // Native innerHeight returns more accurate value for this across platforms,
+ // jQuery version is here as a normalized fallback for platforms like Symbian
+ return window.innerHeight || $( window ).height();
+ }
+ }, $.mobile );
+
+ // Mobile version of data and removeData and hasData methods
+ // ensures all data is set and retrieved using jQuery Mobile's data namespace
+ $.fn.jqmData = function( prop, value ) {
+ var result;
+ if ( typeof prop != "undefined" ) {
+ if ( prop ) {
+ prop = $.mobile.nsNormalize( prop );
+ }
+ result = this.data.apply( this, arguments.length < 2 ? [ prop ] : [ prop, value ] );
+ }
+ return result;
+ };
+
+ $.jqmData = function( elem, prop, value ) {
+ var result;
+ if ( typeof prop != "undefined" ) {
+ result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
+ }
+ return result;
+ };
+
+ $.fn.jqmRemoveData = function( prop ) {
+ return this.removeData( $.mobile.nsNormalize( prop ) );
+ };
+
+ $.jqmRemoveData = function( elem, prop ) {
+ return $.removeData( elem, $.mobile.nsNormalize( prop ) );
+ };
+
+ $.fn.removeWithDependents = function() {
+ $.removeWithDependents( this );
+ };
+
+ $.removeWithDependents = function( elem ) {
+ var $elem = $( elem );
+
+ ( $elem.jqmData('dependents') || $() ).remove();
+ $elem.remove();
+ };
+
+ $.fn.addDependents = function( newDependents ) {
+ $.addDependents( $(this), newDependents );
+ };
+
+ $.addDependents = function( elem, newDependents ) {
+ var dependents = $(elem).jqmData( 'dependents' ) || $();
+
+ $(elem).jqmData( 'dependents', $.merge(dependents, newDependents) );
+ };
+
+ // note that this helper doesn't attempt to handle the callback
+ // or setting of an html elements text, its only purpose is
+ // to return the html encoded version of the text in all cases. (thus the name)
+ $.fn.getEncodedText = function() {
+ return $( "<div/>" ).text( $(this).text() ).html();
+ };
+
+ // fluent helper function for the mobile namespaced equivalent
+ $.fn.jqmEnhanceable = function() {
+ return $.mobile.enhanceable( this );
+ };
+
+ $.fn.jqmHijackable = function() {
+ return $.mobile.hijackable( this );
+ };
+
+ // Monkey-patching Sizzle to filter the :jqmData selector
+ var oldFind = $.find,
+ jqmDataRE = /:jqmData\(([^)]*)\)/g;
+
+ $.find = function( selector, context, ret, extra ) {
+ selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" );
+
+ return oldFind.call( this, selector, context, ret, extra );
+ };
+
+ $.extend( $.find, oldFind );
+
+ $.find.matches = function( expr, set ) {
+ return $.find( expr, null, null, set );
+ };
+
+ $.find.matchesSelector = function( node, expr ) {
+ return $.find( expr, null, null, [ node ] ).length > 0;
+ };
+})( jQuery, this );
+
+
+(function( $, undefined ) {
+
+var $window = $( window ),
+ $html = $( "html" );
+
+/* $.mobile.media method: pass a CSS media type or query and get a bool return
+ note: this feature relies on actual media query support for media queries, though types will work most anywhere
+ examples:
+ $.mobile.media('screen') // tests for screen media type
+ $.mobile.media('screen and (min-width: 480px)') // tests for screen media type with window width > 480px
+ $.mobile.media('@media screen and (-webkit-min-device-pixel-ratio: 2)') // tests for webkit 2x pixel ratio (iPhone 4)
+*/
+$.mobile.media = (function() {
+ // TODO: use window.matchMedia once at least one UA implements it
+ var cache = {},
+ testDiv = $( "<div id='jquery-mediatest'></div>" ),
+ fakeBody = $( "<body>" ).append( testDiv );
+
+ return function( query ) {
+ if ( !( query in cache ) ) {
+ var styleBlock = document.createElement( "style" ),
+ cssrule = "@media " + query + " { #jquery-mediatest { position:absolute; } }";
+
+ //must set type for IE!
+ styleBlock.type = "text/css";
+
+ if ( styleBlock.styleSheet ){
+ styleBlock.styleSheet.cssText = cssrule;
+ } else {
+ styleBlock.appendChild( document.createTextNode(cssrule) );
+ }
+
+ $html.prepend( fakeBody ).prepend( styleBlock );
+ cache[ query ] = testDiv.css( "position" ) === "absolute";
+ fakeBody.add( styleBlock ).remove();
+ }
+ return cache[ query ];
+ };
+})();
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+var fakeBody = $( "<body>" ).prependTo( "html" ),
+ fbCSS = fakeBody[ 0 ].style,
+ vendors = [ "Webkit", "Moz", "O" ],
+ webos = "palmGetResource" in window, //only used to rule out scrollTop
+ opera = window.opera,
+ operamini = window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]",
+ bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB
+
+// thx Modernizr
+function propExists( prop ) {
+ var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
+ props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
+
+ for ( var v in props ){
+ if ( fbCSS[ props[ v ] ] !== undefined ) {
+ return true;
+ }
+ }
+}
+
+function validStyle( prop, value, check_vend ) {
+ var div = document.createElement('div'),
+ uc = function( txt ) {
+ return txt.charAt( 0 ).toUpperCase() + txt.substr( 1 )
+ },
+ vend_pref = function( vend ) {
+ return "-" + vend.charAt( 0 ).toLowerCase() + vend.substr( 1 ) + "-";
+ },
+ check_style = function( vend ) {
+ var vend_prop = vend_pref( vend ) + prop + ": " + value + ";",
+ uc_vend = uc( vend ),
+ propStyle = uc_vend + uc( prop );
+
+ div.setAttribute( "style", vend_prop );
+
+ if( !!div.style[ propStyle ] ) {
+ ret = true;
+ }
+ },
+ check_vends = check_vend ? [ check_vend ] : vendors,
+ ret;
+
+ for( i = 0; i < check_vends.length; i++ ) {
+ check_style( check_vends[i] );
+ }
+ return !!ret;
+}
+
+// Thanks to Modernizr src for this test idea. `perspective` check is limited to Moz to prevent a false positive for 3D transforms on Android.
+function transform3dTest() {
+ var prop = "transform-3d";
+ return validStyle( 'perspective', '10px', 'moz' ) || $.mobile.media( "(-" + vendors.join( "-" + prop + "),(-" ) + "-" + prop + "),(" + prop + ")" );
+}
+
+// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
+function baseTagTest() {
+ var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
+ base = $( "head base" ),
+ fauxEle = null,
+ href = "",
+ link, rebase;
+
+ if ( !base.length ) {
+ base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
+ } else {
+ href = base.attr( "href" );
+ }
+
+ link = $( "<a href='testurl' />" ).prependTo( fakeBody );
+ rebase = link[ 0 ].href;
+ base[ 0 ].href = href || location.pathname;
+
+ if ( fauxEle ) {
+ fauxEle.remove();
+ }
+ return rebase.indexOf( fauxBase ) === 0;
+}
+
+// Thanks Modernizr
+function cssPointerEventsTest() {
+ var element = document.createElement('x'),
+ documentElement = document.documentElement,
+ getComputedStyle = window.getComputedStyle,
+ supports;
+
+ if( !( 'pointerEvents' in element.style ) ){
+ return false;
+ }
+
+ element.style.pointerEvents = 'auto';
+ element.style.pointerEvents = 'x';
+ documentElement.appendChild(element);
+ supports = getComputedStyle &&
+ getComputedStyle( element, '' ).pointerEvents === 'auto';
+ documentElement.removeChild( element );
+ return !!supports;
+}
+
+
+// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
+// allows for inclusion of IE 6+, including Windows Mobile 7
+$.extend( $.mobile, { browser: {} } );
+$.mobile.browser.ie = (function() {
+ var v = 3,
+ div = document.createElement( "div" ),
+ a = div.all || [];
+
+ // added {} to silence closure compiler warnings. registering my dislike of all things
+ // overly clever here for future reference
+ while ( div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->", a[ 0 ] ){};
+
+ return v > 4 ? v : !v;
+})();
+
+
+$.extend( $.support, {
+ orientation: "orientation" in window && "onorientationchange" in window,
+ touch: "ontouchend" in document,
+ cssTransitions: "WebKitTransitionEvent" in window || validStyle( 'transition', 'height 100ms linear' ) && !opera,
+ pushState: "pushState" in history && "replaceState" in history,
+ mediaquery: $.mobile.media( "only all" ),
+ cssPseudoElement: !!propExists( "content" ),
+ touchOverflow: !!propExists( "overflowScrolling" ),
+ cssTransform3d: transform3dTest(),
+ boxShadow: !!propExists( "boxShadow" ) && !bb,
+ scrollTop: ( "pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[ 0 ] ) && !webos && !operamini,
+ dynamicBaseTag: baseTagTest(),
+ cssPointerEvents: cssPointerEventsTest()
+});
+
+fakeBody.remove();
+
+
+// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
+// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
+// Note: This detection below is used as a last resort.
+// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
+var nokiaLTE7_3 = (function(){
+
+ var ua = window.navigator.userAgent;
+
+ //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
+ return ua.indexOf( "Nokia" ) > -1 &&
+ ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
+ ua.indexOf( "AppleWebKit" ) > -1 &&
+ ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
+})();
+
+// Support conditions that must be met in order to proceed
+// default enhanced qualifications are media query support OR IE 7+
+$.mobile.gradeA = function(){
+ return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
+};
+
+$.mobile.ajaxBlacklist =
+ // BlackBerry browsers, pre-webkit
+ window.blackberry && !window.WebKitPoint ||
+ // Opera Mini
+ operamini ||
+ // Symbian webkits pre 7.3
+ nokiaLTE7_3;
+
+// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
+// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
+// This simply reappends the CSS in place, which for some reason makes it apply
+if ( nokiaLTE7_3 ) {
+ $(function() {
+ $( "head link[rel='stylesheet']" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
+ });
+}
+
+// For ruling out shadows via css
+if ( !$.support.boxShadow ) {
+ $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" );
+}
+
+})( jQuery );
+
+(function( $, window, undefined ) {
+
+// add new event shortcuts
+$.each( ( "touchstart touchmove touchend orientationchange throttledresize " +
+ "tap taphold swipe swipeleft swiperight scrollstart scrollstop" ).split( " " ), function( i, name ) {
+
+ $.fn[ name ] = function( fn ) {
+ return fn ? this.bind( name, fn ) : this.trigger( name );
+ };
+
+ $.attrFn[ name ] = true;
+});
+
+var supportTouch = $.support.touch,
+ scrollEvent = "touchmove scroll",
+ touchStartEvent = supportTouch ? "touchstart" : "mousedown",
+ touchStopEvent = supportTouch ? "touchend" : "mouseup",
+ touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
+
+function triggerCustomEvent( obj, eventType, event ) {
+ var originalType = event.type;
+ event.type = eventType;
+ $.event.handle.call( obj, event );
+ event.type = originalType;
+}
+
+// also handles scrollstop
+$.event.special.scrollstart = {
+
+ enabled: true,
+
+ setup: function() {
+
+ var thisObject = this,
+ $this = $( thisObject ),
+ scrolling,
+ timer;
+
+ function trigger( event, state ) {
+ scrolling = state;
+ triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
+ }
+
+ // iPhone triggers scroll after a small delay; use touchmove instead
+ $this.bind( scrollEvent, function( event ) {
+
+ if ( !$.event.special.scrollstart.enabled ) {
+ return;
+ }
+
+ if ( !scrolling ) {
+ trigger( event, true );
+ }
+
+ clearTimeout( timer );
+ timer = setTimeout(function() {
+ trigger( event, false );
+ }, 50 );
+ });
+ }
+};
+
+// also handles taphold
+$.event.special.tap = {
+ setup: function() {
+ var thisObject = this,
+ $this = $( thisObject );
+
+ $this.bind( "vmousedown", function( event ) {
+
+ if ( event.which && event.which !== 1 ) {
+ return false;
+ }
+
+ var origTarget = event.target,
+ origEvent = event.originalEvent,
+ timer;
+
+ function clearTapTimer() {
+ clearTimeout( timer );
+ }
+
+ function clearTapHandlers() {
+ clearTapTimer();
+
+ $this.unbind( "vclick", clickHandler )
+ .unbind( "vmouseup", clearTapTimer );
+ $( document ).unbind( "vmousecancel", clearTapHandlers );
+ }
+
+ function clickHandler(event) {
+ clearTapHandlers();
+
+ // ONLY trigger a 'tap' event if the start target is
+ // the same as the stop target.
+ if ( origTarget == event.target ) {
+ triggerCustomEvent( thisObject, "tap", event );
+ }
+ }
+
+ $this.bind( "vmouseup", clearTapTimer )
+ .bind( "vclick", clickHandler );
+ $( document ).bind( "vmousecancel", clearTapHandlers );
+
+ timer = setTimeout(function() {
+ triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) );
+ }, 750 );
+ });
+ }
+};
+
+// also handles swipeleft, swiperight
+$.event.special.swipe = {
+ scrollSupressionThreshold: 10, // More than this horizontal displacement, and we will suppress scrolling.
+
+ durationThreshold: 1000, // More time than this, and it isn't a swipe.
+
+ horizontalDistanceThreshold: 30, // Swipe horizontal displacement must be more than this.
+
+ verticalDistanceThreshold: 75, // Swipe vertical displacement must be less than this.
+
+ setup: function() {
+ var thisObject = this,
+ $this = $( thisObject );
+
+ $this.bind( touchStartEvent, function( event ) {
+ var data = event.originalEvent.touches ?
+ event.originalEvent.touches[ 0 ] : event,
+ start = {
+ time: ( new Date() ).getTime(),
+ coords: [ data.pageX, data.pageY ],
+ origin: $( event.target )
+ },
+ stop;
+
+ function moveHandler( event ) {
+
+ if ( !start ) {
+ return;
+ }
+
+ var data = event.originalEvent.touches ?
+ event.originalEvent.touches[ 0 ] : event;
+
+ stop = {
+ time: ( new Date() ).getTime(),
+ coords: [ data.pageX, data.pageY ]
+ };
+
+ // prevent scrolling
+ if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
+ event.preventDefault();
+ }
+ }
+
+ $this.bind( touchMoveEvent, moveHandler )
+ .one( touchStopEvent, function( event ) {
+ $this.unbind( touchMoveEvent, moveHandler );
+
+ if ( start && stop ) {
+ if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
+ Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
+ Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
+
+ start.origin.trigger( "swipe" )
+ .trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
+ }
+ }
+ start = stop = undefined;
+ });
+ });
+ }
+};
+
+(function( $, window ) {
+ // "Cowboy" Ben Alman
+
+ var win = $( window ),
+ special_event,
+ get_orientation,
+ last_orientation,
+ initial_orientation_is_landscape,
+ initial_orientation_is_default,
+ portrait_map = { "0": true, "180": true };
+
+ // It seems that some device/browser vendors use window.orientation values 0 and 180 to
+ // denote the "default" orientation. For iOS devices, and most other smart-phones tested,
+ // the default orientation is always "portrait", but in some Android and RIM based tablets,
+ // the default orientation is "landscape". The following code attempts to use the window
+ // dimensions to figure out what the current orientation is, and then makes adjustments
+ // to the to the portrait_map if necessary, so that we can properly decode the
+ // window.orientation value whenever get_orientation() is called.
+ //
+ // Note that we used to use a media query to figure out what the orientation the browser
+ // thinks it is in:
+ //
+ // initial_orientation_is_landscape = $.mobile.media("all and (orientation: landscape)");
+ //
+ // but there was an iPhone/iPod Touch bug beginning with iOS 4.2, up through iOS 5.1,
+ // where the browser *ALWAYS* applied the landscape media query. This bug does not
+ // happen on iPad.
+
+ if ( $.support.orientation ) {
+
+ // Check the window width and height to figure out what the current orientation
+ // of the device is at this moment. Note that we've initialized the portrait map
+ // values to 0 and 180, *AND* we purposely check for landscape so that if we guess
+ // wrong, , we default to the assumption that portrait is the default orientation.
+ // We use a threshold check below because on some platforms like iOS, the iPhone
+ // form-factor can report a larger width than height if the user turns on the
+ // developer console. The actual threshold value is somewhat arbitrary, we just
+ // need to make sure it is large enough to exclude the developer console case.
+
+ var ww = window.innerWidth || $( window ).width(),
+ wh = window.innerHeight || $( window ).height(),
+ landscape_threshold = 50;
+
+ initial_orientation_is_landscape = ww > wh && ( ww - wh ) > landscape_threshold;
+
+
+ // Now check to see if the current window.orientation is 0 or 180.
+ initial_orientation_is_default = portrait_map[ window.orientation ];
+
+ // If the initial orientation is landscape, but window.orientation reports 0 or 180, *OR*
+ // if the initial orientation is portrait, but window.orientation reports 90 or -90, we
+ // need to flip our portrait_map values because landscape is the default orientation for
+ // this device/browser.
+ if ( ( initial_orientation_is_landscape && initial_orientation_is_default ) || ( !initial_orientation_is_landscape && !initial_orientation_is_default ) ) {
+ portrait_map = { "-90": true, "90": true };
+ }
+ }
+
+ $.event.special.orientationchange = special_event = {
+ setup: function() {
+ // If the event is supported natively, return false so that jQuery
+ // will bind to the event using DOM methods.
+ if ( $.support.orientation && $.mobile.orientationChangeEnabled ) {
+ return false;
+ }
+
+ // Get the current orientation to avoid initial double-triggering.
+ last_orientation = get_orientation();
+
+ // Because the orientationchange event doesn't exist, simulate the
+ // event by testing window dimensions on resize.
+ win.bind( "throttledresize", handler );
+ },
+ teardown: function(){
+ // If the event is supported natively, return false so that
+ // jQuery will unbind the event using DOM methods.
+ if ( $.support.orientation && $.mobile.orientationChangeEnabled ) {
+ return false;
+ }
+
+ // Because the orientationchange event doesn't exist, unbind the
+ // resize event handler.
+ win.unbind( "throttledresize", handler );
+ },
+ add: function( handleObj ) {
+ // Save a reference to the bound event handler.
+ var old_handler = handleObj.handler;
+
+
+ handleObj.handler = function( event ) {
+ // Modify event object, adding the .orientation property.
+ event.orientation = get_orientation();
+
+ // Call the originally-bound event handler and return its result.
+ return old_handler.apply( this, arguments );
+ };
+ }
+ };
+
+ // If the event is not supported natively, this handler will be bound to
+ // the window resize event to simulate the orientationchange event.
+ function handler() {
+ // Get the current orientation.
+ var orientation = get_orientation();
+
+ if ( orientation !== last_orientation ) {
+ // The orientation has changed, so trigger the orientationchange event.
+ last_orientation = orientation;
+ win.trigger( "orientationchange" );
+ }
+ }
+
+ // Get the current page orientation. This method is exposed publicly, should it
+ // be needed, as jQuery.event.special.orientationchange.orientation()
+ $.event.special.orientationchange.orientation = get_orientation = function() {
+ var isPortrait = true, elem = document.documentElement;
+
+ // prefer window orientation to the calculation based on screensize as
+ // the actual screen resize takes place before or after the orientation change event
+ // has been fired depending on implementation (eg android 2.3 is before, iphone after).
+ // More testing is required to determine if a more reliable method of determining the new screensize
+ // is possible when orientationchange is fired. (eg, use media queries + element + opacity)
+ if ( $.support.orientation ) {
+ // if the window orientation registers as 0 or 180 degrees report
+ // portrait, otherwise landscape
+ isPortrait = portrait_map[ window.orientation ];
+ } else {
+ isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
+ }
+
+ return isPortrait ? "portrait" : "landscape";
+ };
+
+})( jQuery, window );
+
+
+// throttled resize event
+(function() {
+
+ $.event.special.throttledresize = {
+ setup: function() {
+ $( this ).bind( "resize", handler );
+ },
+ teardown: function(){
+ $( this ).unbind( "resize", handler );
+ }
+ };
+
+ var throttle = 250,
+ handler = function() {
+ curr = ( new Date() ).getTime();
+ diff = curr - lastCall;
+
+ if ( diff >= throttle ) {
+
+ lastCall = curr;
+ $( this ).trigger( "throttledresize" );
+
+ } else {
+
+ if ( heldCall ) {
+ clearTimeout( heldCall );
+ }
+
+ // Promise a held call will still execute
+ heldCall = setTimeout( handler, throttle - diff );
+ }
+ },
+ lastCall = 0,
+ heldCall,
+ curr,
+ diff;
+})();
+
+
+$.each({
+ scrollstop: "scrollstart",
+ taphold: "tap",
+ swipeleft: "swipe",
+ swiperight: "swipe"
+}, function( event, sourceEvent ) {
+
+ $.event.special[ event ] = {
+ setup: function() {
+ $( this ).bind( sourceEvent, $.noop );
+ }
+ };
+});
+
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.page", $.mobile.widget, {
+ options: {
+ theme: "c",
+ domCache: false,
+ keepNativeDefault: ":jqmData(role='none'), :jqmData(role='nojs')"
+ },
+
+ _create: function() {
+
+ var self = this;
+
+ // if false is returned by the callbacks do not create the page
+ if( self._trigger( "beforecreate" ) === false ){
+ return false;
+ }
+
+ self.element
+ .attr( "tabindex", "0" )
+ .addClass( "ui-page ui-body-" + self.options.theme )
+ .bind( "pagebeforehide", function(){
+ self.removeContainerBackground();
+ } )
+ .bind( "pagebeforeshow", function(){
+ self.setContainerBackground();
+ } );
+
+ },
+
+ removeContainerBackground: function(){
+ $.mobile.pageContainer.removeClass( "ui-overlay-" + $.mobile.getInheritedTheme( this.element.parent() ) );
+ },
+
+ // set the page container background to the page theme
+ setContainerBackground: function( theme ){
+ if( this.options.theme ){
+ $.mobile.pageContainer.addClass( "ui-overlay-" + ( theme || this.options.theme ) );
+ }
+ },
+
+ keepNativeSelector: function() {
+ var options = this.options,
+ keepNativeDefined = options.keepNative && $.trim(options.keepNative);
+
+ if( keepNativeDefined && options.keepNative !== options.keepNativeDefault ){
+ return [options.keepNative, options.keepNativeDefault].join(", ");
+ }
+
+ return options.keepNativeDefault;
+ }
+});
+})( jQuery );
+
+
+(function( $, window, undefined ) {
+
+var createHandler = function( sequential ){
+
+ // Default to sequential
+ if( sequential === undefined ){
+ sequential = true;
+ }
+
+ return function( name, reverse, $to, $from ) {
+
+ var deferred = new $.Deferred(),
+ reverseClass = reverse ? " reverse" : "",
+ active = $.mobile.urlHistory.getActive(),
+ toScroll = active.lastScroll || $.mobile.defaultHomeScroll,
+ screenHeight = $.mobile.getScreenHeight(),
+ maxTransitionOverride = $.mobile.maxTransitionWidth !== false && $( window ).width() > $.mobile.maxTransitionWidth,
+ none = !$.support.cssTransitions || maxTransitionOverride || !name || name === "none" || Math.max( $( window ).scrollTop(), toScroll ) > $.mobile.getMaxScrollForTransition(),
+ toPreClass = " ui-page-pre-in",
+ toggleViewportClass = function(){
+ $.mobile.pageContainer.toggleClass( "ui-mobile-viewport-transitioning viewport-" + name );
+ },
+ scrollPage = function(){
+ // By using scrollTo instead of silentScroll, we can keep things better in order
+ // Just to be precautios, disable scrollstart listening like silentScroll would
+ $.event.special.scrollstart.enabled = false;
+
+ window.scrollTo( 0, toScroll );
+
+ // reenable scrollstart listening like silentScroll would
+ setTimeout(function() {
+ $.event.special.scrollstart.enabled = true;
+ }, 150 );
+ },
+ cleanFrom = function(){
+ $from
+ .removeClass( $.mobile.activePageClass + " out in reverse " + name )
+ .height( "" );
+ },
+ startOut = function(){
+ // if it's not sequential, call the doneOut transition to start the TO page animating in simultaneously
+ if( !sequential ){
+ doneOut();
+ }
+ else {
+ $from.animationComplete( doneOut );
+ }
+
+ // Set the from page's height and start it transitioning out
+ // Note: setting an explicit height helps eliminate tiling in the transitions
+ $from
+ .height( screenHeight + $(window ).scrollTop() )
+ .addClass( name + " out" + reverseClass );
+ },
+
+ doneOut = function() {
+
+ if ( $from && sequential ) {
+ cleanFrom();
+ }
+
+ startIn();
+ },
+
+ startIn = function(){
+
+ $to.addClass( $.mobile.activePageClass );
+
+ // Send focus to page as it is now display: block
+ $.mobile.focusPage( $to );
+
+ // Set to page height
+ $to.height( screenHeight + toScroll );
+
+ scrollPage();
+
+ if( !none ){
+ $to.animationComplete( doneIn );
+ }
+
+ $to.addClass( name + " in" + reverseClass );
+
+ if( none ){
+ doneIn();
+ }
+
+ },
+
+ doneIn = function() {
+
+ if ( !sequential ) {
+
+ if( $from ){
+ cleanFrom();
+ }
+ }
+
+ $to
+ .removeClass( "out in reverse " + name )
+ .height( "" );
+
+ toggleViewportClass();
+
+ // In some browsers (iOS5), 3D transitions block the ability to scroll to the desired location during transition
+ // This ensures we jump to that spot after the fact, if we aren't there already.
+ if( $( window ).scrollTop() !== toScroll ){
+ scrollPage();
+ }
+
+ deferred.resolve( name, reverse, $to, $from, true );
+ };
+
+ toggleViewportClass();
+
+ if ( $from && !none ) {
+ startOut();
+ }
+ else {
+ doneOut();
+ }
+
+ return deferred.promise();
+ };
+}
+
+// generate the handlers from the above
+var sequentialHandler = createHandler(),
+ simultaneousHandler = createHandler( false ),
+ defaultGetMaxScrollForTransition = function() {
+ return $.mobile.getScreenHeight() * 3;
+ };
+
+// Make our transition handler the public default.
+$.mobile.defaultTransitionHandler = sequentialHandler;
+
+//transition handler dictionary for 3rd party transitions
+$.mobile.transitionHandlers = {
+ "default": $.mobile.defaultTransitionHandler,
+ "sequential": sequentialHandler,
+ "simultaneous": simultaneousHandler
+};
+
+$.mobile.transitionFallbacks = {};
+
+// Set the getMaxScrollForTransition to default if no implementation was set by user
+$.mobile.getMaxScrollForTransition = $.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition;
+})( jQuery, this );
+
+( function( $, undefined ) {
+
+ //define vars for interal use
+ var $window = $( window ),
+ $html = $( 'html' ),
+ $head = $( 'head' ),
+
+ //url path helpers for use in relative url management
+ path = {
+
+ // This scary looking regular expression parses an absolute URL or its relative
+ // variants (protocol, site, document, query, and hash), into the various
+ // components (protocol, host, path, query, fragment, etc that make up the
+ // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
+ // or String.match, it parses the URL into a results array that looks like this:
+ //
+ // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
+ // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
+ // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
+ // [3]: http://jblas:password@mycompany.com:8080
+ // [4]: http:
+ // [5]: //
+ // [6]: jblas:password@mycompany.com:8080
+ // [7]: jblas:password
+ // [8]: jblas
+ // [9]: password
+ // [10]: mycompany.com:8080
+ // [11]: mycompany.com
+ // [12]: 8080
+ // [13]: /mail/inbox
+ // [14]: /mail/
+ // [15]: inbox
+ // [16]: ?msg=1234&type=unread
+ // [17]: #msg-content
+ //
+ urlParseRE: /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
+
+ //Parse a URL into a structure that allows easy access to
+ //all of the URL components by name.
+ parseUrl: function( url ) {
+ // If we're passed an object, we'll assume that it is
+ // a parsed url object and just return it back to the caller.
+ if ( $.type( url ) === "object" ) {
+ return url;
+ }
+
+ var matches = path.urlParseRE.exec( url || "" ) || [];
+
+ // Create an object that allows the caller to access the sub-matches
+ // by name. Note that IE returns an empty string instead of undefined,
+ // like all other browsers do, so we normalize everything so its consistent
+ // no matter what browser we're running on.
+ return {
+ href: matches[ 0 ] || "",
+ hrefNoHash: matches[ 1 ] || "",
+ hrefNoSearch: matches[ 2 ] || "",
+ domain: matches[ 3 ] || "",
+ protocol: matches[ 4 ] || "",
+ doubleSlash: matches[ 5 ] || "",
+ authority: matches[ 6 ] || "",
+ username: matches[ 8 ] || "",
+ password: matches[ 9 ] || "",
+ host: matches[ 10 ] || "",
+ hostname: matches[ 11 ] || "",
+ port: matches[ 12 ] || "",
+ pathname: matches[ 13 ] || "",
+ directory: matches[ 14 ] || "",
+ filename: matches[ 15 ] || "",
+ search: matches[ 16 ] || "",
+ hash: matches[ 17 ] || ""
+ };
+ },
+
+ //Turn relPath into an asbolute path. absPath is
+ //an optional absolute path which describes what
+ //relPath is relative to.
+ makePathAbsolute: function( relPath, absPath ) {
+ if ( relPath && relPath.charAt( 0 ) === "/" ) {
+ return relPath;
+ }
+
+ relPath = relPath || "";
+ absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
+
+ var absStack = absPath ? absPath.split( "/" ) : [],
+ relStack = relPath.split( "/" );
+ for ( var i = 0; i < relStack.length; i++ ) {
+ var d = relStack[ i ];
+ switch ( d ) {
+ case ".":
+ break;
+ case "..":
+ if ( absStack.length ) {
+ absStack.pop();
+ }
+ break;
+ default:
+ absStack.push( d );
+ break;
+ }
+ }
+ return "/" + absStack.join( "/" );
+ },
+
+ //Returns true if both urls have the same domain.
+ isSameDomain: function( absUrl1, absUrl2 ) {
+ return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
+ },
+
+ //Returns true for any relative variant.
+ isRelativeUrl: function( url ) {
+ // All relative Url variants have one thing in common, no protocol.
+ return path.parseUrl( url ).protocol === "";
+ },
+
+ //Returns true for an absolute url.
+ isAbsoluteUrl: function( url ) {
+ return path.parseUrl( url ).protocol !== "";
+ },
+
+ //Turn the specified realtive URL into an absolute one. This function
+ //can handle all relative variants (protocol, site, document, query, fragment).
+ makeUrlAbsolute: function( relUrl, absUrl ) {
+ if ( !path.isRelativeUrl( relUrl ) ) {
+ return relUrl;
+ }
+
+ var relObj = path.parseUrl( relUrl ),
+ absObj = path.parseUrl( absUrl ),
+ protocol = relObj.protocol || absObj.protocol,
+ doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
+ authority = relObj.authority || absObj.authority,
+ hasPath = relObj.pathname !== "",
+ pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
+ search = relObj.search || ( !hasPath && absObj.search ) || "",
+ hash = relObj.hash;
+
+ return protocol + doubleSlash + authority + pathname + search + hash;
+ },
+
+ //Add search (aka query) params to the specified url.
+ addSearchParams: function( url, params ) {
+ var u = path.parseUrl( url ),
+ p = ( typeof params === "object" ) ? $.param( params ) : params,
+ s = u.search || "?";
+ return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
+ },
+
+ convertUrlToDataUrl: function( absUrl ) {
+ var u = path.parseUrl( absUrl );
+ if ( path.isEmbeddedPage( u ) ) {
+ // For embedded pages, remove the dialog hash key as in getFilePath(),
+ // otherwise the Data Url won't match the id of the embedded Page.
+ return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
+ } else if ( path.isSameDomain( u, documentBase ) ) {
+ return u.hrefNoHash.replace( documentBase.domain, "" ).split( dialogHashKey )[0];
+ }
+ return absUrl;
+ },
+
+ //get path from current hash, or from a file path
+ get: function( newPath ) {
+ if( newPath === undefined ) {
+ newPath = location.hash;
+ }
+ return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
+ },
+
+ //return the substring of a filepath before the sub-page key, for making a server request
+ getFilePath: function( path ) {
+ var splitkey = '&' + $.mobile.subPageUrlKey;
+ return path && path.split( splitkey )[0].split( dialogHashKey )[0];
+ },
+
+ //set location hash to path
+ set: function( path ) {
+ location.hash = path;
+ },
+
+ //test if a given url (string) is a path
+ //NOTE might be exceptionally naive
+ isPath: function( url ) {
+ return ( /\// ).test( url );
+ },
+
+ //return a url path with the window's location protocol/hostname/pathname removed
+ clean: function( url ) {
+ return url.replace( documentBase.domain, "" );
+ },
+
+ //just return the url without an initial #
+ stripHash: function( url ) {
+ return url.replace( /^#/, "" );
+ },
+
+ //remove the preceding hash, any query params, and dialog notations
+ cleanHash: function( hash ) {
+ return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
+ },
+
+ isHashValid: function( hash ) {
+ return /^#[^#]+$/.test(hash);
+ },
+
+ //check whether a url is referencing the same domain, or an external domain or different protocol
+ //could be mailto, etc
+ isExternal: function( url ) {
+ var u = path.parseUrl( url );
+ return u.protocol && u.domain !== documentUrl.domain ? true : false;
+ },
+
+ hasProtocol: function( url ) {
+ return ( /^(:?\w+:)/ ).test( url );
+ },
+
+ //check if the specified url refers to the first page in the main application document.
+ isFirstPageUrl: function( url ) {
+ // We only deal with absolute paths.
+ var u = path.parseUrl( path.makeUrlAbsolute( url, documentBase ) ),
+
+ // Does the url have the same path as the document?
+ samePath = u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ),
+
+ // Get the first page element.
+ fp = $.mobile.firstPage,
+
+ // Get the id of the first page element if it has one.
+ fpId = fp && fp[0] ? fp[0].id : undefined;
+
+ // The url refers to the first page if the path matches the document and
+ // it either has no hash value, or the hash is exactly equal to the id of the
+ // first page element.
+ return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
+ },
+
+ isEmbeddedPage: function( url ) {
+ var u = path.parseUrl( url );
+
+ //if the path is absolute, then we need to compare the url against
+ //both the documentUrl and the documentBase. The main reason for this
+ //is that links embedded within external documents will refer to the
+ //application document, whereas links embedded within the application
+ //document will be resolved against the document base.
+ if ( u.protocol !== "" ) {
+ return ( u.hash && ( u.hrefNoHash === documentUrl.hrefNoHash || ( documentBaseDiffers && u.hrefNoHash === documentBase.hrefNoHash ) ) );
+ }
+ return (/^#/).test( u.href );
+ },
+
+
+ // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+ // requests if the document doing the request was loaded via the file:// protocol.
+ // This is usually to allow the application to "phone home" and fetch app specific
+ // data. We normally let the browser handle external/cross-domain urls, but if the
+ // allowCrossDomainPages option is true, we will allow cross-domain http/https
+ // requests to go through our page loading logic.
+ isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
+ return $.mobile.allowCrossDomainPages
+ && docUrl.protocol === "file:"
+ && reqUrl.search( /^https?:/ ) != -1;
+ }
+ },
+
+ //will be defined when a link is clicked and given an active class
+ $activeClickedLink = null,
+
+ //urlHistory is purely here to make guesses at whether the back or forward button was clicked
+ //and provide an appropriate transition
+ urlHistory = {
+ // Array of pages that are visited during a single page load.
+ // Each has a url and optional transition, title, and pageUrl (which represents the file path, in cases where URL is obscured, such as dialogs)
+ stack: [],
+
+ //maintain an index number for the active page in the stack
+ activeIndex: 0,
+
+ //get active
+ getActive: function() {
+ return urlHistory.stack[ urlHistory.activeIndex ];
+ },
+
+ getPrev: function() {
+ return urlHistory.stack[ urlHistory.activeIndex - 1 ];
+ },
+
+ getNext: function() {
+ return urlHistory.stack[ urlHistory.activeIndex + 1 ];
+ },
+
+ // addNew is used whenever a new page is added
+ addNew: function( url, transition, title, pageUrl, role ) {
+ //if there's forward history, wipe it
+ if( urlHistory.getNext() ) {
+ urlHistory.clearForward();
+ }
+
+ urlHistory.stack.push( {url : url, transition: transition, title: title, pageUrl: pageUrl, role: role } );
+
+ urlHistory.activeIndex = urlHistory.stack.length - 1;
+ },
+
+ //wipe urls ahead of active index
+ clearForward: function() {
+ urlHistory.stack = urlHistory.stack.slice( 0, urlHistory.activeIndex + 1 );
+ },
+
+ directHashChange: function( opts ) {
+ var back , forward, newActiveIndex, prev = this.getActive();
+
+ // check if url is in history and if it's ahead or behind current page
+ $.each( urlHistory.stack, function( i, historyEntry ) {
+
+ //if the url is in the stack, it's a forward or a back
+ if( opts.currentUrl === historyEntry.url ) {
+ //define back and forward by whether url is older or newer than current page
+ back = i < urlHistory.activeIndex;
+ forward = !back;
+ newActiveIndex = i;
+ }
+ });
+
+ // save new page index, null check to prevent falsey 0 result
+ this.activeIndex = newActiveIndex !== undefined ? newActiveIndex : this.activeIndex;
+
+ if( back ) {
+ ( opts.either || opts.isBack )( true );
+ } else if( forward ) {
+ ( opts.either || opts.isForward )( false );
+ }
+ },
+
+ //disable hashchange event listener internally to ignore one change
+ //toggled internally when location.hash is updated to match the url of a successful page load
+ ignoreNextHashChange: false
+ },
+
+ //define first selector to receive focus when a page is shown
+ focusable = "[tabindex],a,button:visible,select:visible,input",
+
+ //queue to hold simultanious page transitions
+ pageTransitionQueue = [],
+
+ //indicates whether or not page is in process of transitioning
+ isPageTransitioning = false,
+
+ //nonsense hash change key for dialogs, so they create a history entry
+ dialogHashKey = "&ui-state=dialog",
+
+ //existing base tag?
+ $base = $head.children( "base" ),
+
+ //tuck away the original document URL minus any fragment.
+ documentUrl = path.parseUrl( location.href ),
+
+ //if the document has an embedded base tag, documentBase is set to its
+ //initial value. If a base tag does not exist, then we default to the documentUrl.
+ documentBase = $base.length ? path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), documentUrl.href ) ) : documentUrl,
+
+ //cache the comparison once.
+ documentBaseDiffers = ( documentUrl.hrefNoHash !== documentBase.hrefNoHash ),
+
+ getScreenHeight = $.mobile.getScreenHeight;
+
+ //base element management, defined depending on dynamic base tag support
+ var base = $.support.dynamicBaseTag ? {
+
+ //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
+ element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
+
+ //set the generated BASE element's href attribute to a new page's base path
+ set: function( href ) {
+ base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
+ },
+
+ //set the generated BASE element's href attribute to a new page's base path
+ reset: function() {
+ base.element.attr( "href", documentBase.hrefNoHash );
+ }
+
+ } : undefined;
+
+/*
+ internal utility functions
+--------------------------------------*/
+
+
+ //direct focus to the page title, or otherwise first focusable element
+ $.mobile.focusPage = function ( page ) {
+ var autofocus = page.find("[autofocus]"),
+ pageTitle = page.find( ".ui-title:eq(0)" );
+
+ if( autofocus.length ) {
+ autofocus.focus();
+ return;
+ }
+
+ if( pageTitle.length ) {
+ pageTitle.focus();
+ }
+ else{
+ page.focus();
+ }
+ }
+
+ //remove active classes after page transition or error
+ function removeActiveLinkClass( forceRemoval ) {
+ if( !!$activeClickedLink && ( !$activeClickedLink.closest( '.ui-page-active' ).length || forceRemoval ) ) {
+ $activeClickedLink.removeClass( $.mobile.activeBtnClass );
+ }
+ $activeClickedLink = null;
+ }
+
+ function releasePageTransitionLock() {
+ isPageTransitioning = false;
+ if( pageTransitionQueue.length > 0 ) {
+ $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
+ }
+ }
+
+ // Save the last scroll distance per page, before it is hidden
+ var setLastScrollEnabled = true,
+ setLastScroll, delayedSetLastScroll;
+
+ setLastScroll = function() {
+ // this barrier prevents setting the scroll value based on the browser
+ // scrolling the window based on a hashchange
+ if( !setLastScrollEnabled ) {
+ return;
+ }
+
+ var active = $.mobile.urlHistory.getActive();
+
+ if( active ) {
+ var lastScroll = $window.scrollTop();
+
+ // Set active page's lastScroll prop.
+ // If the location we're scrolling to is less than minScrollBack, let it go.
+ active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
+ }
+ };
+
+ // bind to scrollstop to gather scroll position. The delay allows for the hashchange
+ // event to fire and disable scroll recording in the case where the browser scrolls
+ // to the hash targets location (sometimes the top of the page). once pagechange fires
+ // getLastScroll is again permitted to operate
+ delayedSetLastScroll = function() {
+ setTimeout( setLastScroll, 100 );
+ };
+
+ // disable an scroll setting when a hashchange has been fired, this only works
+ // because the recording of the scroll position is delayed for 100ms after
+ // the browser might have changed the position because of the hashchange
+ $window.bind( $.support.pushState ? "popstate" : "hashchange", function() {
+ setLastScrollEnabled = false;
+ });
+
+ // handle initial hashchange from chrome :(
+ $window.one( $.support.pushState ? "popstate" : "hashchange", function() {
+ setLastScrollEnabled = true;
+ });
+
+ // wait until the mobile page container has been determined to bind to pagechange
+ $window.one( "pagecontainercreate", function(){
+ // once the page has changed, re-enable the scroll recording
+ $.mobile.pageContainer.bind( "pagechange", function() {
+
+ setLastScrollEnabled = true;
+
+ // remove any binding that previously existed on the get scroll
+ // which may or may not be different than the scroll element determined for
+ // this page previously
+ $window.unbind( "scrollstop", delayedSetLastScroll );
+
+ // determine and bind to the current scoll element which may be the window
+ // or in the case of touch overflow the element with touch overflow
+ $window.bind( "scrollstop", delayedSetLastScroll );
+ });
+ });
+
+ // bind to scrollstop for the first page as "pagechange" won't be fired in that case
+ $window.bind( "scrollstop", delayedSetLastScroll );
+
+ //function for transitioning between two existing pages
+ function transitionPages( toPage, fromPage, transition, reverse ) {
+
+ if( fromPage ) {
+ //trigger before show/hide events
+ fromPage.data( "page" )._trigger( "beforehide", null, { nextPage: toPage } );
+ }
+
+ toPage.data( "page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
+
+ //clear page loader
+ $.mobile.hidePageLoadingMsg();
+
+ // If transition is defined, check if css 3D transforms are supported, and if not, if a fallback is specified
+ if( transition && !$.support.cssTransform3d && $.mobile.transitionFallbacks[ transition ] ){
+ transition = $.mobile.transitionFallbacks[ transition ];
+ }
+
+ //find the transition handler for the specified transition. If there
+ //isn't one in our transitionHandlers dictionary, use the default one.
+ //call the handler immediately to kick-off the transition.
+ var th = $.mobile.transitionHandlers[ transition || "default" ] || $.mobile.defaultTransitionHandler,
+ promise = th( transition, reverse, toPage, fromPage );
+
+ promise.done(function() {
+
+ //trigger show/hide events
+ if( fromPage ) {
+ fromPage.data( "page" )._trigger( "hide", null, { nextPage: toPage } );
+ }
+
+ //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
+ toPage.data( "page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
+ });
+
+ return promise;
+ }
+
+ //simply set the active page's minimum height to screen height, depending on orientation
+ function resetActivePageHeight(){
+ var aPage = $( "." + $.mobile.activePageClass ),
+ aPagePadT = parseFloat( aPage.css( "padding-top" ) ),
+ aPagePadB = parseFloat( aPage.css( "padding-bottom" ) ),
+ aPageBorderT = parseFloat( aPage.css( "border-top-width" ) ),
+ aPageBorderB = parseFloat( aPage.css( "border-bottom-width" ) );
+
+ aPage.css( "min-height", getScreenHeight() - aPagePadT - aPagePadB - aPageBorderT - aPageBorderB );
+ }
+
+ //shared page enhancements
+ function enhancePage( $page, role ) {
+ // If a role was specified, make sure the data-role attribute
+ // on the page element is in sync.
+ if( role ) {
+ $page.attr( "data-" + $.mobile.ns + "role", role );
+ }
+
+ //run page plugin
+ $page.page();
+ }
+
+/* exposed $.mobile methods */
+
+ //animation complete callback
+ $.fn.animationComplete = function( callback ) {
+ if( $.support.cssTransitions ) {
+ return $( this ).one( 'webkitAnimationEnd animationend', callback );
+ }
+ else{
+ // defer execution for consistency between webkit/non webkit
+ setTimeout( callback, 0 );
+ return $( this );
+ }
+ };
+
+ //expose path object on $.mobile
+ $.mobile.path = path;
+
+ //expose base object on $.mobile
+ $.mobile.base = base;
+
+ //history stack
+ $.mobile.urlHistory = urlHistory;
+
+ $.mobile.dialogHashKey = dialogHashKey;
+
+
+
+ //enable cross-domain page support
+ $.mobile.allowCrossDomainPages = false;
+
+ //return the original document url
+ $.mobile.getDocumentUrl = function(asParsedObject) {
+ return asParsedObject ? $.extend( {}, documentUrl ) : documentUrl.href;
+ };
+
+ //return the original document base url
+ $.mobile.getDocumentBase = function(asParsedObject) {
+ return asParsedObject ? $.extend( {}, documentBase ) : documentBase.href;
+ };
+
+ $.mobile._bindPageRemove = function() {
+ var page = $(this);
+
+ // when dom caching is not enabled or the page is embedded bind to remove the page on hide
+ if( !page.data("page").options.domCache
+ && page.is(":jqmData(external-page='true')") ) {
+
+ page.bind( 'pagehide.remove', function() {
+ var $this = $( this ),
+ prEvent = new $.Event( "pageremove" );
+
+ $this.trigger( prEvent );
+
+ if( !prEvent.isDefaultPrevented() ){
+ $this.removeWithDependents();
+ }
+ });
+ }
+ };
+
+ // Load a page into the DOM.
+ $.mobile.loadPage = function( url, options ) {
+ // This function uses deferred notifications to let callers
+ // know when the page is done loading, or if an error has occurred.
+ var deferred = $.Deferred(),
+
+ // The default loadPage options with overrides specified by
+ // the caller.
+ settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
+
+ // The DOM element for the page after it has been loaded.
+ page = null,
+
+ // If the reloadPage option is true, and the page is already
+ // in the DOM, dupCachedPage will be set to the page element
+ // so that it can be removed after the new version of the
+ // page is loaded off the network.
+ dupCachedPage = null,
+
+ // determine the current base url
+ findBaseWithDefault = function(){
+ var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
+ return closestBase || documentBase.hrefNoHash;
+ },
+
+ // The absolute version of the URL passed into the function. This
+ // version of the URL may contain dialog/subpage params in it.
+ absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );
+
+
+ // If the caller provided data, and we're using "get" request,
+ // append the data to the URL.
+ if ( settings.data && settings.type === "get" ) {
+ absUrl = path.addSearchParams( absUrl, settings.data );
+ settings.data = undefined;
+ }
+
+ // If the caller is using a "post" request, reloadPage must be true
+ if( settings.data && settings.type === "post" ){
+ settings.reloadPage = true;
+ }
+
+ // The absolute version of the URL minus any dialog/subpage params.
+ // In otherwords the real URL of the page to be loaded.
+ var fileUrl = path.getFilePath( absUrl ),
+
+ // The version of the Url actually stored in the data-url attribute of
+ // the page. For embedded pages, it is just the id of the page. For pages
+ // within the same domain as the document base, it is the site relative
+ // path. For cross-domain pages (Phone Gap only) the entire absolute Url
+ // used to load the page.
+ dataUrl = path.convertUrlToDataUrl( absUrl );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Check to see if the page already exists in the DOM.
+ page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
+
+ // If we failed to find the page, check to see if the url is a
+ // reference to an embedded page. If so, it may have been dynamically
+ // injected by a developer, in which case it would be lacking a data-url
+ // attribute and in need of enhancement.
+ if ( page.length === 0 && dataUrl && !path.isPath( dataUrl ) ) {
+ page = settings.pageContainer.children( "#" + dataUrl )
+ .attr( "data-" + $.mobile.ns + "url", dataUrl );
+ }
+
+ // If we failed to find a page in the DOM, check the URL to see if it
+ // refers to the first page in the application. If it isn't a reference
+ // to the first page and refers to non-existent embedded page, error out.
+ if ( page.length === 0 ) {
+ if ( $.mobile.firstPage && path.isFirstPageUrl( fileUrl ) ) {
+ // Check to make sure our cached-first-page is actually
+ // in the DOM. Some user deployed apps are pruning the first
+ // page from the DOM for various reasons, we check for this
+ // case here because we don't want a first-page with an id
+ // falling through to the non-existent embedded page error
+ // case. If the first-page is not in the DOM, then we let
+ // things fall through to the ajax loading code below so
+ // that it gets reloaded.
+ if ( $.mobile.firstPage.parent().length ) {
+ page = $( $.mobile.firstPage );
+ }
+ } else if ( path.isEmbeddedPage( fileUrl ) ) {
+ deferred.reject( absUrl, options );
+ return deferred.promise();
+ }
+ }
+
+ // Reset base to the default document base.
+ if ( base ) {
+ base.reset();
+ }
+
+ // If the page we are interested in is already in the DOM,
+ // and the caller did not indicate that we should force a
+ // reload of the file, we are done. Otherwise, track the
+ // existing page as a duplicated.
+ if ( page.length ) {
+ if ( !settings.reloadPage ) {
+ enhancePage( page, settings.role );
+ deferred.resolve( absUrl, options, page );
+ return deferred.promise();
+ }
+ dupCachedPage = page;
+ }
+
+ var mpc = settings.pageContainer,
+ pblEvent = new $.Event( "pagebeforeload" ),
+ triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };
+
+ // Let listeners know we're about to load a page.
+ mpc.trigger( pblEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ if( pblEvent.isDefaultPrevented() ){
+ return deferred.promise();
+ }
+
+ if ( settings.showLoadMsg ) {
+
+ // This configurable timeout allows cached pages a brief delay to load without showing a message
+ var loadMsgDelay = setTimeout(function(){
+ $.mobile.showPageLoadingMsg();
+ }, settings.loadMsgDelay ),
+
+ // Shared logic for clearing timeout and removing message.
+ hideMsg = function(){
+
+ // Stop message show timer
+ clearTimeout( loadMsgDelay );
+
+ // Hide loading message
+ $.mobile.hidePageLoadingMsg();
+ };
+ }
+
+ if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
+ deferred.reject( absUrl, options );
+ } else {
+ // Load the new page.
+ $.ajax({
+ url: fileUrl,
+ type: settings.type,
+ data: settings.data,
+ dataType: "html",
+ success: function( html, textStatus, xhr ) {
+ //pre-parse html to check for a data-url,
+ //use it as the new fileUrl, base path, etc
+ var all = $( "<div></div>" ),
+
+ //page title regexp
+ newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
+
+ // TODO handle dialogs again
+ pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)" ),
+ dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
+
+
+ // data-url must be provided for the base tag so resource requests can be directed to the
+ // correct url. loading into a temprorary element makes these requests immediately
+ if( pageElemRegex.test( html )
+ && RegExp.$1
+ && dataUrlRegex.test( RegExp.$1 )
+ && RegExp.$1 ) {
+ url = fileUrl = path.getFilePath( RegExp.$1 );
+ }
+
+ if ( base ) {
+ base.set( fileUrl );
+ }
+
+ //workaround to allow scripts to execute when included in page divs
+ all.get( 0 ).innerHTML = html;
+ page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
+
+ //if page elem couldn't be found, create one and insert the body element's contents
+ if( !page.length ){
+ page = $( "<div data-" + $.mobile.ns + "role='page'>" + html.split( /<\/?body[^>]*>/gmi )[1] + "</div>" );
+ }
+
+ if ( newPageTitle && !page.jqmData( "title" ) ) {
+ if ( ~newPageTitle.indexOf( "&" ) ) {
+ newPageTitle = $( "<div>" + newPageTitle + "</div>" ).text();
+ }
+ page.jqmData( "title", newPageTitle );
+ }
+
+ //rewrite src and href attrs to use a base url
+ if( !$.support.dynamicBaseTag ) {
+ var newPath = path.get( fileUrl );
+ page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
+ var thisAttr = $( this ).is( '[href]' ) ? 'href' :
+ $(this).is('[src]') ? 'src' : 'action',
+ thisUrl = $( this ).attr( thisAttr );
+
+ // XXX_jblas: We need to fix this so that it removes the document
+ // base URL, and then prepends with the new page URL.
+ //if full path exists and is same, chop it - helps IE out
+ thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
+
+ if( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
+ $( this ).attr( thisAttr, newPath + thisUrl );
+ }
+ });
+ }
+
+ //append to page and enhance
+ // TODO taging a page with external to make sure that embedded pages aren't removed
+ // by the various page handling code is bad. Having page handling code in many
+ // places is bad. Solutions post 1.0
+ page
+ .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
+ .attr( "data-" + $.mobile.ns + "external-page", true )
+ .appendTo( settings.pageContainer );
+
+ // wait for page creation to leverage options defined on widget
+ page.one( 'pagecreate', $.mobile._bindPageRemove );
+
+ enhancePage( page, settings.role );
+
+ // Enhancing the page may result in new dialogs/sub pages being inserted
+ // into the DOM. If the original absUrl refers to a sub-page, that is the
+ // real page we are interested in.
+ if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
+ page = settings.pageContainer.children( ":jqmData(url='" + dataUrl + "')" );
+ }
+
+ //bind pageHide to removePage after it's hidden, if the page options specify to do so
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+ hideMsg();
+ }
+
+ // Add the page reference and xhr to our triggerData.
+ triggerData.xhr = xhr;
+ triggerData.textStatus = textStatus;
+ triggerData.page = page;
+
+ // Let listeners know the page loaded successfully.
+ settings.pageContainer.trigger( "pageload", triggerData );
+
+ deferred.resolve( absUrl, options, page, dupCachedPage );
+ },
+ error: function( xhr, textStatus, errorThrown ) {
+ //set base back to current path
+ if( base ) {
+ base.set( path.get() );
+ }
+
+ // Add error info to our triggerData.
+ triggerData.xhr = xhr;
+ triggerData.textStatus = textStatus;
+ triggerData.errorThrown = errorThrown;
+
+ var plfEvent = new $.Event( "pageloadfailed" );
+
+ // Let listeners know the page load failed.
+ settings.pageContainer.trigger( plfEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ // Note that it is the responsibility of the listener/handler
+ // that called preventDefault(), to resolve/reject the
+ // deferred object within the triggerData.
+ if( plfEvent.isDefaultPrevented() ){
+ return;
+ }
+
+ // Remove loading message.
+ if ( settings.showLoadMsg ) {
+
+ // Remove loading message.
+ hideMsg();
+
+ // show error message
+ $.mobile.showPageLoadingMsg( $.mobile.pageLoadErrorMessageTheme, $.mobile.pageLoadErrorMessage, true );
+
+ // hide after delay
+ setTimeout( $.mobile.hidePageLoadingMsg, 1500 );
+ }
+
+ deferred.reject( absUrl, options );
+ }
+ });
+ }
+
+ return deferred.promise();
+ };
+
+ $.mobile.loadPage.defaults = {
+ type: "get",
+ data: undefined,
+ reloadPage: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ showLoadMsg: false,
+ pageContainer: undefined,
+ loadMsgDelay: 50 // This delay allows loads that pull from browser cache to occur without showing the loading message.
+ };
+
+ // Show a specific page in the page container.
+ $.mobile.changePage = function( toPage, options ) {
+ // If we are in the midst of a transition, queue the current request.
+ // We'll call changePage() once we're done with the current transition to
+ // service the request.
+ if( isPageTransitioning ) {
+ pageTransitionQueue.unshift( arguments );
+ return;
+ }
+
+ var settings = $.extend( {}, $.mobile.changePage.defaults, options );
+
+ // Make sure we have a pageContainer to work with.
+ settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
+
+ // Make sure we have a fromPage.
+ settings.fromPage = settings.fromPage || $.mobile.activePage;
+
+ var mpc = settings.pageContainer,
+ pbcEvent = new $.Event( "pagebeforechange" ),
+ triggerData = { toPage: toPage, options: settings };
+
+ // Let listeners know we're about to change the current page.
+ mpc.trigger( pbcEvent, triggerData );
+
+ // If the default behavior is prevented, stop here!
+ if( pbcEvent.isDefaultPrevented() ){
+ return;
+ }
+
+ // We allow "pagebeforechange" observers to modify the toPage in the trigger
+ // data to allow for redirects. Make sure our toPage is updated.
+
+ toPage = triggerData.toPage;
+
+ // Set the isPageTransitioning flag to prevent any requests from
+ // entering this method while we are in the midst of loading a page
+ // or transitioning.
+
+ isPageTransitioning = true;
+
+ // If the caller passed us a url, call loadPage()
+ // to make sure it is loaded into the DOM. We'll listen
+ // to the promise object it returns so we know when
+ // it is done loading or if an error ocurred.
+ if ( typeof toPage == "string" ) {
+ $.mobile.loadPage( toPage, settings )
+ .done(function( url, options, newPage, dupCachedPage ) {
+ isPageTransitioning = false;
+ options.duplicateCachedPage = dupCachedPage;
+ $.mobile.changePage( newPage, options );
+ })
+ .fail(function( url, options ) {
+ isPageTransitioning = false;
+
+ //clear out the active button state
+ removeActiveLinkClass( true );
+
+ //release transition lock so navigation is free again
+ releasePageTransitionLock();
+ settings.pageContainer.trigger( "pagechangefailed", triggerData );
+ });
+ return;
+ }
+
+ // If we are going to the first-page of the application, we need to make
+ // sure settings.dataUrl is set to the application document url. This allows
+ // us to avoid generating a document url with an id hash in the case where the
+ // first-page of the document has an id attribute specified.
+ if ( toPage[ 0 ] === $.mobile.firstPage[ 0 ] && !settings.dataUrl ) {
+ settings.dataUrl = documentUrl.hrefNoHash;
+ }
+
+ // The caller passed us a real page DOM element. Update our
+ // internal state and then trigger a transition to the page.
+ var fromPage = settings.fromPage,
+ url = ( settings.dataUrl && path.convertUrlToDataUrl( settings.dataUrl ) ) || toPage.jqmData( "url" ),
+ // The pageUrl var is usually the same as url, except when url is obscured as a dialog url. pageUrl always contains the file path
+ pageUrl = url,
+ fileUrl = path.getFilePath( url ),
+ active = urlHistory.getActive(),
+ activeIsInitialPage = urlHistory.activeIndex === 0,
+ historyDir = 0,
+ pageTitle = document.title,
+ isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
+
+ // By default, we prevent changePage requests when the fromPage and toPage
+ // are the same element, but folks that generate content manually/dynamically
+ // and reuse pages want to be able to transition to the same page. To allow
+ // this, they will need to change the default value of allowSamePageTransition
+ // to true, *OR*, pass it in as an option when they manually call changePage().
+ // It should be noted that our default transition animations assume that the
+ // formPage and toPage are different elements, so they may behave unexpectedly.
+ // It is up to the developer that turns on the allowSamePageTransitiona option
+ // to either turn off transition animations, or make sure that an appropriate
+ // animation transition is used.
+ if( fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition ) {
+ isPageTransitioning = false;
+ mpc.trigger( "pagechange", triggerData );
+
+ // Even if there is no page change to be done, we should keep the urlHistory in sync with the hash changes
+ if( settings.fromHashChange ) {
+ urlHistory.directHashChange({
+ currentUrl: url,
+ isBack: function() {},
+ isForward: function() {}
+ });
+ }
+
+ return;
+ }
+
+ // We need to make sure the page we are given has already been enhanced.
+ enhancePage( toPage, settings.role );
+
+ // If the changePage request was sent from a hashChange event, check to see if the
+ // page is already within the urlHistory stack. If so, we'll assume the user hit
+ // the forward/back button and will try to match the transition accordingly.
+ if( settings.fromHashChange ) {
+ urlHistory.directHashChange({
+ currentUrl: url,
+ isBack: function() { historyDir = -1; },
+ isForward: function() { historyDir = 1; }
+ });
+ }
+
+ // Kill the keyboard.
+ // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
+ // we should be tracking focus with a delegate() handler so we already have
+ // the element in hand at this point.
+ // Wrap this in a try/catch block since IE9 throw "Unspecified error" if document.activeElement
+ // is undefined when we are in an IFrame.
+ try {
+ if(document.activeElement && document.activeElement.nodeName.toLowerCase() != 'body') {
+ $(document.activeElement).blur();
+ } else {
+ $( "input:focus, textarea:focus, select:focus" ).blur();
+ }
+ } catch(e) {}
+
+ // Record whether we are at a place in history where a dialog used to be - if so, do not add a new history entry and do not change the hash either
+ var alreadyThere = false;
+
+ // If we're displaying the page as a dialog, we don't want the url
+ // for the dialog content to be used in the hash. Instead, we want
+ // to append the dialogHashKey to the url of the current page.
+ if ( isDialog && active ) {
+ // on the initial page load active.url is undefined and in that case should
+ // be an empty string. Moving the undefined -> empty string back into
+ // urlHistory.addNew seemed imprudent given undefined better represents
+ // the url state
+
+ // If we are at a place in history that once belonged to a dialog, reuse
+ // this state without adding to urlHistory and without modifying the hash.
+ // However, if a dialog is already displayed at this point, and we're
+ // about to display another dialog, then we must add another hash and
+ // history entry on top so that one may navigate back to the original dialog
+ if ( active.url.indexOf( dialogHashKey ) > -1 && !$.mobile.activePage.is( ".ui-dialog" ) ) {
+ settings.changeHash = false;
+ alreadyThere = true;
+ }
+
+ url = ( active.url || "" ) + dialogHashKey;
+
+ // tack on another dialogHashKey if this is the same as the initial hash
+ // this makes sure that a history entry is created for this dialog
+ if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
+ url += dialogHashKey;
+ }
+ }
+
+ // Set the location hash.
+ if( settings.changeHash !== false && url ) {
+ //disable hash listening temporarily
+ urlHistory.ignoreNextHashChange = true;
+ //update hash and history
+ path.set( url );
+ }
+
+ // if title element wasn't found, try the page div data attr too
+ // If this is a deep-link or a reload ( active === undefined ) then just use pageTitle
+ var newPageTitle = ( !active )? pageTitle : toPage.jqmData( "title" ) || toPage.children(":jqmData(role='header')").find(".ui-title" ).getEncodedText();
+ if( !!newPageTitle && pageTitle == document.title ) {
+ pageTitle = newPageTitle;
+ }
+ if ( !toPage.jqmData( "title" ) ) {
+ toPage.jqmData( "title", pageTitle );
+ }
+
+ // Make sure we have a transition defined.
+ settings.transition = settings.transition
+ || ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined )
+ || ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
+
+ //add page to history stack if it's not back or forward
+ if( !historyDir && !alreadyThere ) {
+ urlHistory.addNew( url, settings.transition, pageTitle, pageUrl, settings.role );
+ }
+
+ //set page title
+ document.title = urlHistory.getActive().title;
+
+ //set "toPage" as activePage
+ $.mobile.activePage = toPage;
+
+ // If we're navigating back in the URL history, set reverse accordingly.
+ settings.reverse = settings.reverse || historyDir < 0;
+
+ transitionPages( toPage, fromPage, settings.transition, settings.reverse )
+ .done(function( name, reverse, $to, $from, alreadyFocused ) {
+ removeActiveLinkClass();
+
+ //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
+ if ( settings.duplicateCachedPage ) {
+ settings.duplicateCachedPage.remove();
+ }
+
+ // Send focus to the newly shown page. Moved from promise .done binding in transitionPages
+ // itself to avoid ie bug that reports offsetWidth as > 0 (core check for visibility)
+ // despite visibility: hidden addresses issue #2965
+ // https://github.com/jquery/jquery-mobile/issues/2965
+ if( !alreadyFocused ){
+ $.mobile.focusPage( toPage );
+ }
+
+ releasePageTransitionLock();
+
+ // Let listeners know we're all done changing the current page.
+ mpc.trigger( "pagechange", triggerData );
+ });
+ };
+
+ $.mobile.changePage.defaults = {
+ transition: undefined,
+ reverse: false,
+ changeHash: true,
+ fromHashChange: false,
+ role: undefined, // By default we rely on the role defined by the @data-role attribute.
+ duplicateCachedPage: undefined,
+ pageContainer: undefined,
+ showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
+ dataUrl: undefined,
+ fromPage: undefined,
+ allowSamePageTransition: false
+ };
+
+/* Event Bindings - hashchange, submit, and click */
+ function findClosestLink( ele )
+ {
+ while ( ele ) {
+ // Look for the closest element with a nodeName of "a".
+ // Note that we are checking if we have a valid nodeName
+ // before attempting to access it. This is because the
+ // node we get called with could have originated from within
+ // an embedded SVG document where some symbol instance elements
+ // don't have nodeName defined on them, or strings are of type
+ // SVGAnimatedString.
+ if ( ( typeof ele.nodeName === "string" ) && ele.nodeName.toLowerCase() == "a" ) {
+ break;
+ }
+ ele = ele.parentNode;
+ }
+ return ele;
+ }
+
+ // The base URL for any given element depends on the page it resides in.
+ function getClosestBaseUrl( ele )
+ {
+ // Find the closest page and extract out its url.
+ var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
+ base = documentBase.hrefNoHash;
+
+ if ( !url || !path.isPath( url ) ) {
+ url = base;
+ }
+
+ return path.makeUrlAbsolute( url, base);
+ }
+
+ //The following event bindings should be bound after mobileinit has been triggered
+ //the following deferred is resolved in the init file
+ $.mobile.navreadyDeferred = $.Deferred();
+ $.mobile.navreadyDeferred.done( function(){
+ //bind to form submit events, handle with Ajax
+ $( document ).delegate( "form", "submit", function( event ) {
+ var $this = $( this );
+
+ if( !$.mobile.ajaxEnabled ||
+ // test that the form is, itself, ajax false
+ $this.is(":jqmData(ajax='false')") ||
+ // test that $.mobile.ignoreContentEnabled is set and
+ // the form or one of it's parents is ajax=false
+ !$this.jqmHijackable().length ) {
+ return;
+ }
+
+ var type = $this.attr( "method" ),
+ target = $this.attr( "target" ),
+ url = $this.attr( "action" );
+
+ // If no action is specified, browsers default to using the
+ // URL of the document containing the form. Since we dynamically
+ // pull in pages from external documents, the form should submit
+ // to the URL for the source document of the page containing
+ // the form.
+ if ( !url ) {
+ // Get the @data-url for the page containing the form.
+ url = getClosestBaseUrl( $this );
+ if ( url === documentBase.hrefNoHash ) {
+ // The url we got back matches the document base,
+ // which means the page must be an internal/embedded page,
+ // so default to using the actual document url as a browser
+ // would.
+ url = documentUrl.hrefNoSearch;
+ }
+ }
+
+ url = path.makeUrlAbsolute( url, getClosestBaseUrl($this) );
+
+ if(( path.isExternal( url ) && !path.isPermittedCrossDomainRequest(documentUrl, url)) || target ) {
+ return;
+ }
+
+ $.mobile.changePage(
+ url,
+ {
+ type: type && type.length && type.toLowerCase() || "get",
+ data: $this.serialize(),
+ transition: $this.jqmData( "transition" ),
+ direction: $this.jqmData( "direction" ),
+ reloadPage: true
+ }
+ );
+ event.preventDefault();
+ });
+
+ //add active state on vclick
+ $( document ).bind( "vclick", function( event ) {
+ // if this isn't a left click we don't care. Its important to note
+ // that when the virtual event is generated it will create the which attr
+ if ( event.which > 1 || !$.mobile.linkBindingEnabled ) {
+ return;
+ }
+
+ var link = findClosestLink( event.target );
+
+ // split from the previous return logic to avoid find closest where possible
+ // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
+ // can be avoided
+ if ( !$(link).jqmHijackable().length ) {
+ return;
+ }
+
+ if ( link ) {
+ if ( path.parseUrl( link.getAttribute( "href" ) || "#" ).hash !== "#" ) {
+ removeActiveLinkClass( true );
+ $activeClickedLink = $( link ).closest( ".ui-btn" ).not( ".ui-disabled" );
+ $activeClickedLink.addClass( $.mobile.activeBtnClass );
+ }
+ }
+ });
+
+ // click routing - direct to HTTP or Ajax, accordingly
+ $( document ).bind( "click", function( event ) {
+ if( !$.mobile.linkBindingEnabled ){
+ return;
+ }
+
+ var link = findClosestLink( event.target ), $link = $( link ), httpCleanup;
+
+ // If there is no link associated with the click or its not a left
+ // click we want to ignore the click
+ // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
+ // can be avoided
+ if ( !link || event.which > 1 || !$link.jqmHijackable().length ) {
+ return;
+ }
+
+ //remove active link class if external (then it won't be there if you come back)
+ httpCleanup = function(){
+ window.setTimeout( function() { removeActiveLinkClass( true ); }, 200 );
+ };
+
+ //if there's a data-rel=back attr, go back in history
+ if( $link.is( ":jqmData(rel='back')" ) ) {
+ window.history.back();
+ return false;
+ }
+
+ var baseUrl = getClosestBaseUrl( $link ),
+
+ //get href, if defined, otherwise default to empty hash
+ href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
+
+ //if ajax is disabled, exit early
+ if( !$.mobile.ajaxEnabled && !path.isEmbeddedPage( href ) ){
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ // XXX_jblas: Ideally links to application pages should be specified as
+ // an url to the application document with a hash that is either
+ // the site relative path or id to the page. But some of the
+ // internal code that dynamically generates sub-pages for nested
+ // lists and select dialogs, just write a hash in the link they
+ // create. This means the actual URL path is based on whatever
+ // the current value of the base tag is at the time this code
+ // is called. For now we are just assuming that any url with a
+ // hash in it is an application page reference.
+ if ( href.search( "#" ) != -1 ) {
+ href = href.replace( /[^#]*#/, "" );
+ if ( !href ) {
+ //link was an empty hash meant purely
+ //for interaction, so we ignore it.
+ event.preventDefault();
+ return;
+ } else if ( path.isPath( href ) ) {
+ //we have apath so make it the href we want to load.
+ href = path.makeUrlAbsolute( href, baseUrl );
+ } else {
+ //we have a simple id so use the documentUrl as its base.
+ href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
+ }
+ }
+
+ // Should we handle this link, or let the browser deal with it?
+ var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
+
+ // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
+ // requests if the document doing the request was loaded via the file:// protocol.
+ // This is usually to allow the application to "phone home" and fetch app specific
+ // data. We normally let the browser handle external/cross-domain urls, but if the
+ // allowCrossDomainPages option is true, we will allow cross-domain http/https
+ // requests to go through our page loading logic.
+
+ //check for protocol or rel and its not an embedded page
+ //TODO overlap in logic from isExternal, rel=external check should be
+ // moved into more comprehensive isExternalLink
+ isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !path.isPermittedCrossDomainRequest(documentUrl, href) );
+
+ if( isExternal ) {
+ httpCleanup();
+ //use default click handling
+ return;
+ }
+
+ //use ajax
+ var transition = $link.jqmData( "transition" ),
+ direction = $link.jqmData( "direction" ),
+ reverse = ( direction && direction === "reverse" ) ||
+ // deprecated - remove by 1.0
+ $link.jqmData( "back" ),
+
+ //this may need to be more specific as we use data-rel more
+ role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
+
+ $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role } );
+ event.preventDefault();
+ });
+
+ //prefetch pages when anchors with data-prefetch are encountered
+ $( document ).delegate( ".ui-page", "pageshow.prefetch", function() {
+ var urls = [];
+ $( this ).find( "a:jqmData(prefetch)" ).each(function(){
+ var $link = $(this),
+ url = $link.attr( "href" );
+
+ if ( url && $.inArray( url, urls ) === -1 ) {
+ urls.push( url );
+
+ $.mobile.loadPage( url, {role: $link.attr("data-" + $.mobile.ns + "rel")} );
+ }
+ });
+ });
+
+ $.mobile._handleHashChange = function( hash ) {
+ //find first page via hash
+ var to = path.stripHash( hash ),
+ //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
+ transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined,
+
+ // default options for the changPage calls made after examining the current state
+ // of the page and the hash
+ changePageOptions = {
+ transition: transition,
+ changeHash: false,
+ fromHashChange: true
+ };
+
+ if ( 0 === urlHistory.stack.length ) {
+ urlHistory.initialDst = to;
+ }
+
+ //if listening is disabled (either globally or temporarily), or it's a dialog hash
+ if( !$.mobile.hashListeningEnabled || urlHistory.ignoreNextHashChange ) {
+ urlHistory.ignoreNextHashChange = false;
+ return;
+ }
+
+ // special case for dialogs
+ if( urlHistory.stack.length > 1 && to.indexOf( dialogHashKey ) > -1 && urlHistory.initialDst !== to ) {
+
+ // If current active page is not a dialog skip the dialog and continue
+ // in the same direction
+ if(!$.mobile.activePage.is( ".ui-dialog" )) {
+ //determine if we're heading forward or backward and continue accordingly past
+ //the current dialog
+ urlHistory.directHashChange({
+ currentUrl: to,
+ isBack: function() { window.history.back(); },
+ isForward: function() { window.history.forward(); }
+ });
+
+ // prevent changePage()
+ return;
+ } else {
+ // if the current active page is a dialog and we're navigating
+ // to a dialog use the dialog objected saved in the stack
+ urlHistory.directHashChange({
+ currentUrl: to,
+
+ // regardless of the direction of the history change
+ // do the following
+ either: function( isBack ) {
+ var active = $.mobile.urlHistory.getActive();
+
+ to = active.pageUrl;
+
+ // make sure to set the role, transition and reversal
+ // as most of this is lost by the domCache cleaning
+ $.extend( changePageOptions, {
+ role: active.role,
+ transition: active.transition,
+ reverse: isBack
+ });
+ }
+ });
+ }
+ }
+
+ //if to is defined, load it
+ if ( to ) {
+ // At this point, 'to' can be one of 3 things, a cached page element from
+ // a history stack entry, an id, or site-relative/absolute URL. If 'to' is
+ // an id, we need to resolve it against the documentBase, not the location.href,
+ // since the hashchange could've been the result of a forward/backward navigation
+ // that crosses from an external page/dialog to an internal page/dialog.
+ to = ( typeof to === "string" && !path.isPath( to ) ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : to;
+ $.mobile.changePage( to, changePageOptions );
+ } else {
+ //there's no hash, go to the first page in the dom
+ $.mobile.changePage( $.mobile.firstPage, changePageOptions );
+ }
+ };
+
+ //hashchange event handler
+ $window.bind( "hashchange", function( e, triggered ) {
+ $.mobile._handleHashChange( location.hash );
+ });
+
+ //set page min-heights to be device specific
+ $( document ).bind( "pageshow", resetActivePageHeight );
+ $( window ).bind( "throttledresize", resetActivePageHeight );
+
+ });//navreadyDeferred done callback
+
+})( jQuery );
+
+( function( $, window ) {
+ // For now, let's Monkeypatch this onto the end of $.mobile._registerInternalEvents
+ // Scope self to pushStateHandler so we can reference it sanely within the
+ // methods handed off as event handlers
+ var pushStateHandler = {},
+ self = pushStateHandler,
+ $win = $( window ),
+ url = $.mobile.path.parseUrl( location.href ),
+ mobileinitDeferred = $.Deferred(),
+ domreadyDeferred = $.Deferred();
+
+ $( document ).ready( $.proxy( domreadyDeferred, "resolve" ) );
+
+ $( document ).one( "mobileinit", $.proxy( mobileinitDeferred, "resolve" ) );
+
+ $.extend( pushStateHandler, {
+ // TODO move to a path helper, this is rather common functionality
+ initialFilePath: (function() {
+ return url.pathname + url.search;
+ })(),
+
+ hashChangeTimeout: 200,
+
+ hashChangeEnableTimer: undefined,
+
+ initialHref: url.hrefNoHash,
+
+ state: function() {
+ return {
+ hash: location.hash || "#" + self.initialFilePath,
+ title: document.title,
+
+ // persist across refresh
+ initialHref: self.initialHref
+ };
+ },
+
+ resetUIKeys: function( url ) {
+ var dialog = $.mobile.dialogHashKey,
+ subkey = "&" + $.mobile.subPageUrlKey,
+ dialogIndex = url.indexOf( dialog );
+
+ if( dialogIndex > -1 ) {
+ url = url.slice( 0, dialogIndex ) + "#" + url.slice( dialogIndex );
+ } else if( url.indexOf( subkey ) > -1 ) {
+ url = url.split( subkey ).join( "#" + subkey );
+ }
+
+ return url;
+ },
+
+ // TODO sort out a single barrier to hashchange functionality
+ nextHashChangePrevented: function( value ) {
+ $.mobile.urlHistory.ignoreNextHashChange = value;
+ self.onHashChangeDisabled = value;
+ },
+
+ // on hash change we want to clean up the url
+ // NOTE this takes place *after* the vanilla navigation hash change
+ // handling has taken place and set the state of the DOM
+ onHashChange: function( e ) {
+ // disable this hash change
+ if( self.onHashChangeDisabled ){
+ return;
+ }
+
+ var href, state,
+ hash = location.hash,
+ isPath = $.mobile.path.isPath( hash ),
+ resolutionUrl = isPath ? location.href : $.mobile.getDocumentUrl();
+
+ hash = isPath ? hash.replace( "#", "" ) : hash;
+
+
+ // propulate the hash when its not available
+ state = self.state();
+
+ // make the hash abolute with the current href
+ href = $.mobile.path.makeUrlAbsolute( hash, resolutionUrl );
+
+ if ( isPath ) {
+ href = self.resetUIKeys( href );
+ }
+
+ // replace the current url with the new href and store the state
+ // Note that in some cases we might be replacing an url with the
+ // same url. We do this anyways because we need to make sure that
+ // all of our history entries have a state object associated with
+ // them. This allows us to work around the case where window.history.back()
+ // is called to transition from an external page to an embedded page.
+ // In that particular case, a hashchange event is *NOT* generated by the browser.
+ // Ensuring each history entry has a state object means that onPopState()
+ // will always trigger our hashchange callback even when a hashchange event
+ // is not fired.
+ history.replaceState( state, document.title, href );
+ },
+
+ // on popstate (ie back or forward) we need to replace the hash that was there previously
+ // cleaned up by the additional hash handling
+ onPopState: function( e ) {
+ var poppedState = e.originalEvent.state,
+ fromHash, toHash, hashChanged;
+
+ // if there's no state its not a popstate we care about, eg chrome's initial popstate
+ if( poppedState ) {
+ // if we get two pop states in under this.hashChangeTimeout
+ // make sure to clear any timer set for the previous change
+ clearTimeout( self.hashChangeEnableTimer );
+
+ // make sure to enable hash handling for the the _handleHashChange call
+ self.nextHashChangePrevented( false );
+
+ // change the page based on the hash in the popped state
+ $.mobile._handleHashChange( poppedState.hash );
+
+ // prevent any hashchange in the next self.hashChangeTimeout
+ self.nextHashChangePrevented( true );
+
+ // re-enable hash change handling after swallowing a possible hash
+ // change event that comes on all popstates courtesy of browsers like Android
+ self.hashChangeEnableTimer = setTimeout( function() {
+ self.nextHashChangePrevented( false );
+ }, self.hashChangeTimeout);
+ }
+ },
+
+ init: function() {
+ $win.bind( "hashchange", self.onHashChange );
+
+ // Handle popstate events the occur through history changes
+ $win.bind( "popstate", self.onPopState );
+
+ // if there's no hash, we need to replacestate for returning to home
+ if ( location.hash === "" ) {
+ history.replaceState( self.state(), document.title, location.href );
+ }
+ }
+ });
+
+ // We need to init when "mobileinit", "domready", and "navready" have all happened
+ $.when( domreadyDeferred, mobileinitDeferred, $.mobile.navreadyDeferred ).done( function() {
+ if( $.mobile.pushStateEnabled && $.support.pushState ){
+ pushStateHandler.init();
+ }
+ });
+})( jQuery, this );
+
+/*
+* fallback transition for pop in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.pop = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for slide in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+// Use the simultaneous transition handler for slide transitions
+$.mobile.transitionHandlers.slide = $.mobile.transitionHandlers.simultaneous;
+
+// Set the slide transition's fallback to "fade"
+$.mobile.transitionFallbacks.slide = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for slidedown in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.slidedown = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for slideup in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.slideup = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for flip in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.flip = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for flow in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.flow = "fade";
+
+})( jQuery, this );
+
+/*
+* fallback transition for turn in non-3D supporting browsers (which tend to handle complex transitions poorly in general
+*/
+
+(function( $, window, undefined ) {
+
+$.mobile.transitionFallbacks.turn = "fade";
+
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.degradeInputs = {
+ color: false,
+ date: false,
+ datetime: false,
+ "datetime-local": false,
+ email: false,
+ month: false,
+ number: false,
+ range: "number",
+ search: "text",
+ tel: false,
+ time: false,
+ url: false,
+ week: false
+};
+
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+
+ var page = $.mobile.closestPageData($(e.target)), options;
+
+ if( !page ) {
+ return;
+ }
+
+ options = page.options;
+
+ // degrade inputs to avoid poorly implemented native functionality
+ $( e.target ).find( "input" ).not( page.keepNativeSelector() ).each(function() {
+ var $this = $( this ),
+ type = this.getAttribute( "type" ),
+ optType = options.degradeInputs[ type ] || "text";
+
+ if ( options.degradeInputs[ type ] ) {
+ var html = $( "<div>" ).html( $this.clone() ).html(),
+ // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
+ hasType = html.indexOf( " type=" ) > -1,
+ findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/,
+ repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );
+
+ $this.replaceWith( html.replace( findstr, repstr ) );
+ }
+ });
+
+});
+
+})( jQuery );
+
+(function( $, window, undefined ) {
+
+$.widget( "mobile.dialog", $.mobile.widget, {
+ options: {
+ closeBtnText : "Close",
+ overlayTheme : "a",
+ initSelector : ":jqmData(role='dialog')"
+ },
+ _create: function() {
+ var self = this,
+ $el = this.element,
+ headerCloseButton = $( "<a href='#' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" ),
+ dialogWrap = $("<div/>", {
+ "role" : "dialog",
+ "class" : "ui-dialog-contain ui-corner-all ui-overlay-shadow"
+ });
+
+ $el.addClass( "ui-dialog ui-overlay-" + this.options.overlayTheme );
+
+ // Class the markup for dialog styling
+ // Set aria role
+ $el
+ .wrapInner( dialogWrap )
+ .children()
+ .find( ":jqmData(role='header')" )
+ .prepend( headerCloseButton )
+ .end()
+ .children( ':first-child')
+ .addClass( "ui-corner-top" )
+ .end()
+ .children( ":last-child" )
+ .addClass( "ui-corner-bottom" );
+
+ // this must be an anonymous function so that select menu dialogs can replace
+ // the close method. This is a change from previously just defining data-rel=back
+ // on the button and letting nav handle it
+ //
+ // Use click rather than vclick in order to prevent the possibility of unintentionally
+ // reopening the dialog if the dialog opening item was directly under the close button.
+ headerCloseButton.bind( "click", function() {
+ self.close();
+ });
+
+ /* bind events
+ - clicks and submits should use the closing transition that the dialog opened with
+ unless a data-transition is specified on the link/form
+ - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
+ */
+ $el.bind( "vclick submit", function( event ) {
+ var $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" ),
+ active;
+
+ if ( $target.length && !$target.jqmData( "transition" ) ) {
+
+ active = $.mobile.urlHistory.getActive() || {};
+
+ $target.attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
+ .attr( "data-" + $.mobile.ns + "direction", "reverse" );
+ }
+ })
+ .bind( "pagehide", function( e, ui ) {
+ self._isClosed = false;
+ $( this ).find( "." + $.mobile.activeBtnClass ).not( ".ui-slider-bg" ).removeClass( $.mobile.activeBtnClass );
+ })
+ // Override the theme set by the page plugin on pageshow
+ .bind( "pagebeforeshow", function(){
+ if( self.options.overlayTheme ){
+ self.element
+ .page( "removeContainerBackground" )
+ .page( "setContainerBackground", self.options.overlayTheme );
+ }
+ });
+ },
+
+ // Close method goes back in history
+ close: function() {
+ if ( !this._isClosed ) {
+ this._isClosed = true;
+ if ( $.mobile.hashListeningEnabled ) {
+ window.history.back();
+ }
+ else {
+ $.mobile.changePage( $.mobile.urlHistory.getPrev().url );
+ }
+ }
+ }
+});
+
+//auto self-init widgets
+$( document ).delegate( $.mobile.dialog.prototype.options.initSelector, "pagecreate", function(){
+ $.mobile.dialog.prototype.enhance( this );
+});
+
+})( jQuery, this );
+
+(function( $, undefined ) {
+
+$.mobile.page.prototype.options.backBtnText = "Back";
+$.mobile.page.prototype.options.addBackBtn = false;
+$.mobile.page.prototype.options.backBtnTheme = null;
+$.mobile.page.prototype.options.headerTheme = "a";
+$.mobile.page.prototype.options.footerTheme = "a";
+$.mobile.page.prototype.options.contentTheme = null;
+
+// NOTE bind used to force this binding to run before the buttonMarkup binding
+// which expects .ui-footer top be applied in its gigantic selector
+// TODO remove the buttonMarkup giant selector and move it to the various modules
+// on which it depends
+$( document ).bind( "pagecreate", function( e ) {
+ var $page = $( e.target ),
+ o = $page.data( "page" ).options,
+ pageRole = $page.jqmData( "role" ),
+ pageTheme = o.theme;
+
+ $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", $page )
+ .jqmEnhanceable()
+ .each(function() {
+
+ var $this = $( this ),
+ role = $this.jqmData( "role" ),
+ theme = $this.jqmData( "theme" ),
+ contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ),
+ $headeranchors,
+ leftbtn,
+ rightbtn,
+ backBtn;
+
+ $this.addClass( "ui-" + role );
+
+ //apply theming and markup modifications to page,header,content,footer
+ if ( role === "header" || role === "footer" ) {
+
+ var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
+
+ $this
+ //add theme class
+ .addClass( "ui-bar-" + thisTheme )
+ // Add ARIA role
+ .attr( "role", role === "header" ? "banner" : "contentinfo" );
+
+ if( role === "header") {
+ // Right,left buttons
+ $headeranchors = $this.children( "a" );
+ leftbtn = $headeranchors.hasClass( "ui-btn-left" );
+ rightbtn = $headeranchors.hasClass( "ui-btn-right" );
+
+ leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
+
+ rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
+ }
+
+ // Auto-add back btn on pages beyond first view
+ if ( o.addBackBtn &&
+ role === "header" &&
+ $( ".ui-page" ).length > 1 &&
+ $page.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
+ !leftbtn ) {
+
+ backBtn = $( "<a href='javascript:void(0);' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" )
+ // If theme is provided, override default inheritance
+ .attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme )
+ .prependTo( $this );
+ }
+
+ // Page title
+ $this.children( "h1, h2, h3, h4, h5, h6" )
+ .addClass( "ui-title" )
+ // Regardless of h element number in src, it becomes h1 for the enhanced page
+ .attr({
+ "role": "heading",
+ "aria-level": "1"
+ });
+
+ } else if ( role === "content" ) {
+ if ( contentTheme ) {
+ $this.addClass( "ui-body-" + ( contentTheme ) );
+ }
+
+ // Add ARIA role
+ $this.attr( "role", "main" );
+ }
+ });
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+// filter function removes whitespace between label and form element so we can use inline-block (nodeType 3 = text)
+$.fn.fieldcontain = function( options ) {
+ return this
+ .addClass( "ui-field-contain ui-body ui-br" )
+ .contents().filter( function() {
+ return ( this.nodeType === 3 && !/\S/.test( this.nodeValue ) );
+ }).remove();
+};
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='fieldcontain')", e.target ).jqmEnhanceable().fieldcontain();
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.fn.grid = function( options ) {
+ return this.each(function() {
+
+ var $this = $( this ),
+ o = $.extend({
+ grid: null
+ },options),
+ $kids = $this.children(),
+ gridCols = {solo:1, a:2, b:3, c:4, d:5},
+ grid = o.grid,
+ iterator;
+
+ if ( !grid ) {
+ if ( $kids.length <= 5 ) {
+ for ( var letter in gridCols ) {
+ if ( gridCols[ letter ] === $kids.length ) {
+ grid = letter;
+ }
+ }
+ } else {
+ grid = "a";
+ $this.addClass( "ui-grid-duo" );
+ }
+ }
+ iterator = gridCols[grid];
+
+ $this.addClass( "ui-grid-" + grid );
+
+ $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
+
+ if ( iterator > 1 ) {
+ $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
+ }
+ if ( iterator > 2 ) {
+ $kids.filter( ":nth-child(3n+3)" ).addClass( "ui-block-c" );
+ }
+ if ( iterator > 3 ) {
+ $kids.filter( ":nth-child(4n+4)" ).addClass( "ui-block-d" );
+ }
+ if ( iterator > 4 ) {
+ $kids.filter( ":nth-child(5n+5)" ).addClass( "ui-block-e" );
+ }
+ });
+};
+})( jQuery );
+
+(function( $, undefined ) {
+
+$( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='nojs')", e.target ).addClass( "ui-nojs" );
+
+});
+
+})( jQuery );
+
+( function( $, undefined ) {
+
+$.fn.buttonMarkup = function( options ) {
+ var $workingSet = this;
+
+ // Enforce options to be of type string
+ options = ( options && ( $.type( options ) == "object" ) )? options : {};
+ for ( var i = 0; i < $workingSet.length; i++ ) {
+ var el = $workingSet.eq( i ),
+ e = el[ 0 ],
+ o = $.extend( {}, $.fn.buttonMarkup.defaults, {
+ icon: options.icon !== undefined ? options.icon : el.jqmData( "icon" ),
+ iconpos: options.iconpos !== undefined ? options.iconpos : el.jqmData( "iconpos" ),
+ theme: options.theme !== undefined ? options.theme : el.jqmData( "theme" ) || $.mobile.getInheritedTheme( el, "c" ),
+ inline: options.inline !== undefined ? options.inline : el.jqmData( "inline" ),
+ shadow: options.shadow !== undefined ? options.shadow : el.jqmData( "shadow" ),
+ corners: options.corners !== undefined ? options.corners : el.jqmData( "corners" ),
+ iconshadow: options.iconshadow !== undefined ? options.iconshadow : el.jqmData( "iconshadow" ),
+ mini: options.mini !== undefined ? options.mini : el.jqmData( "mini" )
+ }, options ),
+
+ // Classes Defined
+ innerClass = "ui-btn-inner",
+ textClass = "ui-btn-text",
+ buttonClass, iconClass,
+ // Button inner markup
+ buttonInner,
+ buttonText,
+ buttonIcon,
+ buttonElements;
+
+ $.each(o, function(key, value) {
+ e.setAttribute( "data-" + $.mobile.ns + key, value );
+ el.jqmData(key, value);
+ });
+
+ // Check if this element is already enhanced
+ buttonElements = $.data(((e.tagName === "INPUT" || e.tagName === "BUTTON") ? e.parentNode : e), "buttonElements");
+
+ if (buttonElements) {
+ e = buttonElements.outer;
+ el = $(e);
+ buttonInner = buttonElements.inner;
+ buttonText = buttonElements.text;
+ // We will recreate this icon below
+ $(buttonElements.icon).remove();
+ buttonElements.icon = null;
+ }
+ else {
+ buttonInner = document.createElement( o.wrapperEls );
+ buttonText = document.createElement( o.wrapperEls );
+ }
+ buttonIcon = o.icon ? document.createElement( "span" ) : null;
+
+ if ( attachEvents && !buttonElements) {
+ attachEvents();
+ }
+
+ // if not, try to find closest theme container
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( el, "c" );
+ }
+
+ buttonClass = "ui-btn ui-btn-up-" + o.theme;
+ buttonClass += o.inline ? " ui-btn-inline" : "";
+ buttonClass += o.shadow ? " ui-shadow" : "";
+ buttonClass += o.corners ? " ui-btn-corner-all" : "";
+
+ if ( o.mini !== undefined ) {
+ // Used to control styling in headers/footers, where buttons default to `mini` style.
+ buttonClass += o.mini ? " ui-mini" : " ui-fullsize";
+ }
+
+ if ( o.inline !== undefined ) {
+ // Used to control styling in headers/footers, where buttons default to `mini` style.
+ buttonClass += o.inline === false ? " ui-btn-block" : " ui-btn-inline";
+ }
+
+
+ if ( o.icon ) {
+ o.icon = "ui-icon-" + o.icon;
+ o.iconpos = o.iconpos || "left";
+
+ iconClass = "ui-icon " + o.icon;
+
+ if ( o.iconshadow ) {
+ iconClass += " ui-icon-shadow";
+ }
+ }
+
+ if ( o.iconpos ) {
+ buttonClass += " ui-btn-icon-" + o.iconpos;
+
+ if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
+ el.attr( "title", el.getEncodedText() );
+ }
+ }
+
+ innerClass += o.corners ? " ui-btn-corner-all" : "";
+
+ if ( o.iconpos && o.iconpos === "notext" && !el.attr( "title" ) ) {
+ el.attr( "title", el.getEncodedText() );
+ }
+
+ if ( buttonElements ) {
+ el.removeClass( buttonElements.bcls || "" );
+ }
+ el.removeClass( "ui-link" ).addClass( buttonClass );
+
+ buttonInner.className = innerClass;
+
+ buttonText.className = textClass;
+ if ( !buttonElements ) {
+ buttonInner.appendChild( buttonText );
+ }
+ if ( buttonIcon ) {
+ buttonIcon.className = iconClass;
+ if ( !(buttonElements && buttonElements.icon) ) {
+ buttonIcon.appendChild( document.createTextNode("\u00a0") );
+ buttonInner.appendChild( buttonIcon );
+ }
+ }
+
+ while ( e.firstChild && !buttonElements) {
+ buttonText.appendChild( e.firstChild );
+ }
+
+ if ( !buttonElements ) {
+ e.appendChild( buttonInner );
+ }
+
+ // Assign a structure containing the elements of this button to the elements of this button. This
+ // will allow us to recognize this as an already-enhanced button in future calls to buttonMarkup().
+ buttonElements = {
+ bcls : buttonClass,
+ outer : e,
+ inner : buttonInner,
+ text : buttonText,
+ icon : buttonIcon
+ };
+
+ $.data(e, 'buttonElements', buttonElements);
+ $.data(buttonInner, 'buttonElements', buttonElements);
+ $.data(buttonText, 'buttonElements', buttonElements);
+ if (buttonIcon) {
+ $.data(buttonIcon, 'buttonElements', buttonElements);
+ }
+ }
+
+ return this;
+};
+
+$.fn.buttonMarkup.defaults = {
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ wrapperEls: "span"
+};
+
+function closestEnabledButton( element ) {
+ var cname;
+
+ while ( element ) {
+ // Note that we check for typeof className below because the element we
+ // handed could be in an SVG DOM where className on SVG elements is defined to
+ // be of a different type (SVGAnimatedString). We only operate on HTML DOM
+ // elements, so we look for plain "string".
+ cname = ( typeof element.className === 'string' ) && (element.className + ' ');
+ if ( cname && cname.indexOf("ui-btn ") > -1 && cname.indexOf("ui-disabled ") < 0 ) {
+ break;
+ }
+
+ element = element.parentNode;
+ }
+
+ return element;
+}
+
+var attachEvents = function() {
+ var hoverDelay = $.mobile.buttonMarkup.hoverDelay, hov, foc;
+
+ $( document ).bind( {
+ "vmousedown vmousecancel vmouseup vmouseover vmouseout focus blur scrollstart": function( event ) {
+ var theme,
+ $btn = $( closestEnabledButton( event.target ) ),
+ evt = event.type;
+
+ if ( $btn.length ) {
+ theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
+
+ if ( evt === "vmousedown" ) {
+ if ( $.support.touch ) {
+ hov = setTimeout(function() {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+ }, hoverDelay );
+ } else {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
+ }
+ } else if ( evt === "vmousecancel" || evt === "vmouseup" ) {
+ $btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+ } else if ( evt === "vmouseover" || evt === "focus" ) {
+ if ( $.support.touch ) {
+ foc = setTimeout(function() {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+ }, hoverDelay );
+ } else {
+ $btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
+ }
+ } else if ( evt === "vmouseout" || evt === "blur" || evt === "scrollstart" ) {
+ $btn.removeClass( "ui-btn-hover-" + theme + " ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
+ if ( hov ) {
+ clearTimeout( hov );
+ }
+ if ( foc ) {
+ clearTimeout( foc );
+ }
+ }
+ }
+ },
+ "focusin focus": function( event ){
+ $( closestEnabledButton( event.target ) ).addClass( $.mobile.focusClass );
+ },
+ "focusout blur": function( event ){
+ $( closestEnabledButton( event.target ) ).removeClass( $.mobile.focusClass );
+ }
+ });
+
+ attachEvents = null;
+};
+
+//links in bars, or those with data-role become buttons
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+
+ $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
+ .not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .buttonMarkup();
+});
+
+})( jQuery );
+
+
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsible", $.mobile.widget, {
+ options: {
+ expandCueText: " click to expand contents",
+ collapseCueText: " click to collapse contents",
+ collapsed: true,
+ heading: "h1,h2,h3,h4,h5,h6,legend",
+ theme: null,
+ contentTheme: null,
+ iconTheme: "d",
+ mini: false,
+ initSelector: ":jqmData(role='collapsible')"
+ },
+ _create: function() {
+
+ var $el = this.element,
+ o = this.options,
+ collapsible = $el.addClass( "ui-collapsible" ),
+ collapsibleHeading = $el.children( o.heading ).first(),
+ collapsibleContent = collapsible.wrapInner( "<div class='ui-collapsible-content'></div>" ).find( ".ui-collapsible-content" ),
+ collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" );
+
+ // Replace collapsibleHeading if it's a legend
+ if ( collapsibleHeading.is( "legend" ) ) {
+ collapsibleHeading = $( "<div role='heading'>"+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
+ collapsibleHeading.next().remove();
+ }
+
+ // If we are in a collapsible set
+ if ( collapsibleSet.length ) {
+ // Inherit the theme from collapsible-set
+ if ( !o.theme ) {
+ o.theme = collapsibleSet.jqmData("theme") || $.mobile.getInheritedTheme( collapsibleSet, "c" );
+ }
+ // Inherit the content-theme from collapsible-set
+ if ( !o.contentTheme ) {
+ o.contentTheme = collapsibleSet.jqmData( "content-theme" );
+ }
+
+ // Gets the preference icon position in the set
+ if ( !o.iconPos ) {
+ o.iconPos = collapsibleSet.jqmData( "iconpos" );
+ }
+
+ if( !o.mini ) {
+ o.mini = collapsibleSet.jqmData( "mini" );
+ }
+ }
+ collapsibleContent.addClass( ( o.contentTheme ) ? ( "ui-body-" + o.contentTheme ) : "");
+
+ collapsibleHeading
+ //drop heading in before content
+ .insertBefore( collapsibleContent )
+ //modify markup & attributes
+ .addClass( "ui-collapsible-heading" )
+ .append( "<span class='ui-collapsible-heading-status'></span>" )
+ .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
+ .find( "a" )
+ .first()
+ .buttonMarkup({
+ shadow: false,
+ corners: false,
+ iconpos: $el.jqmData( "iconpos" ) || o.iconPos || "left",
+ icon: "plus",
+ mini: o.mini,
+ theme: o.theme
+ })
+ .add( ".ui-btn-inner", $el )
+ .addClass( "ui-corner-top ui-corner-bottom" );
+
+ //events
+ collapsible
+ .bind( "expand collapse", function( event ) {
+ if ( !event.isDefaultPrevented() ) {
+
+ event.preventDefault();
+
+ var $this = $( this ),
+ isCollapse = ( event.type === "collapse" ),
+ contentTheme = o.contentTheme;
+
+ collapsibleHeading
+ .toggleClass( "ui-collapsible-heading-collapsed", isCollapse)
+ .find( ".ui-collapsible-heading-status" )
+ .text( isCollapse ? o.expandCueText : o.collapseCueText )
+ .end()
+ .find( ".ui-icon" )
+ .toggleClass( "ui-icon-minus", !isCollapse )
+ .toggleClass( "ui-icon-plus", isCollapse )
+ .end()
+ .find( "a" ).first().removeClass( $.mobile.activeBtnClass );
+
+ $this.toggleClass( "ui-collapsible-collapsed", isCollapse );
+ collapsibleContent.toggleClass( "ui-collapsible-content-collapsed", isCollapse ).attr( "aria-hidden", isCollapse );
+
+ if ( contentTheme && ( !collapsibleSet.length || collapsible.jqmData( "collapsible-last" ) ) ) {
+ collapsibleHeading
+ .find( "a" ).first().add( collapsibleHeading.find( ".ui-btn-inner" ) )
+ .toggleClass( "ui-corner-bottom", isCollapse );
+ collapsibleContent.toggleClass( "ui-corner-bottom", !isCollapse );
+ }
+ collapsibleContent.trigger( "updatelayout" );
+ }
+ })
+ .trigger( o.collapsed ? "collapse" : "expand" );
+
+ collapsibleHeading
+ .bind( "tap", function( event ) {
+ collapsibleHeading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
+ })
+ .bind( "click", function( event ) {
+
+ var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ?
+ "expand" : "collapse";
+
+ collapsible.trigger( type );
+
+ event.preventDefault();
+ event.stopPropagation();
+ });
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.collapsible.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.collapsibleset", $.mobile.widget, {
+ options: {
+ initSelector: ":jqmData(role='collapsible-set')"
+ },
+ _create: function() {
+ var $el = this.element.addClass( "ui-collapsible-set" ),
+ o = this.options;
+
+ // Inherit the theme from collapsible-set
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( $el, "c" );
+ }
+ // Inherit the content-theme from collapsible-set
+ if ( !o.contentTheme ) {
+ o.contentTheme = $el.jqmData( "content-theme" );
+ }
+
+ if ( !o.corners ) {
+ o.corners = $el.jqmData( "corners" ) === undefined ? true : false;
+ }
+
+ // Initialize the collapsible set if it's not already initialized
+ if ( !$el.jqmData( "collapsiblebound" ) ) {
+ $el
+ .jqmData( "collapsiblebound", true )
+ .bind( "expand collapse", function( event ) {
+ var isCollapse = ( event.type === "collapse" ),
+ collapsible = $( event.target ).closest( ".ui-collapsible" ),
+ widget = collapsible.data( "collapsible" ),
+ contentTheme = widget.options.contentTheme;
+ if ( contentTheme && collapsible.jqmData( "collapsible-last" ) ) {
+ collapsible.find( widget.options.heading ).first()
+ .find( "a" ).first()
+ .toggleClass( "ui-corner-bottom", isCollapse )
+ .find( ".ui-btn-inner" )
+ .toggleClass( "ui-corner-bottom", isCollapse );
+ collapsible.find( ".ui-collapsible-content" ).toggleClass( "ui-corner-bottom", !isCollapse );
+ }
+ })
+ .bind( "expand", function( event ) {
+ $( event.target )
+ .closest( ".ui-collapsible" )
+ .siblings( ".ui-collapsible" )
+ .trigger( "collapse" );
+ });
+ }
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ refresh: function() {
+ var $el = this.element,
+ o = this.options,
+ collapsiblesInSet = $el.children( ":jqmData(role='collapsible')" );
+
+ $.mobile.collapsible.prototype.enhance( collapsiblesInSet.not( ".ui-collapsible" ) );
+
+ // clean up borders
+ collapsiblesInSet.each( function() {
+ $( this ).find( $.mobile.collapsible.prototype.options.heading )
+ .find( "a" ).first()
+ .removeClass( "ui-corner-top ui-corner-bottom" )
+ .find( ".ui-btn-inner" )
+ .removeClass( "ui-corner-top ui-corner-bottom" );
+ });
+
+ collapsiblesInSet.first()
+ .find( "a" )
+ .first()
+ .addClass( o.corners ? "ui-corner-top" : "" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-top" );
+
+ collapsiblesInSet.last()
+ .jqmData( "collapsible-last", true )
+ .find( "a" )
+ .first()
+ .addClass( o.corners ? "ui-corner-bottom" : "" )
+ .find( ".ui-btn-inner" )
+ .addClass( "ui-corner-bottom" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.collapsibleset.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.navbar", $.mobile.widget, {
+ options: {
+ iconpos: "top",
+ grid: null,
+ initSelector: ":jqmData(role='navbar')"
+ },
+
+ _create: function(){
+
+ var $navbar = this.element,
+ $navbtns = $navbar.find( "a" ),
+ iconpos = $navbtns.filter( ":jqmData(icon)" ).length ?
+ this.options.iconpos : undefined;
+
+ $navbar.addClass( "ui-navbar ui-mini" )
+ .attr( "role","navigation" )
+ .find( "ul" )
+ .jqmEnhanceable()
+ .grid({ grid: this.options.grid });
+
+ $navbtns.buttonMarkup({
+ corners: false,
+ shadow: false,
+ inline: true,
+ iconpos: iconpos
+ });
+
+ $navbar.delegate( "a", "vclick", function( event ) {
+ if( !$(event.target).hasClass("ui-disabled") ) {
+ $navbtns.removeClass( $.mobile.activeBtnClass );
+ $( this ).addClass( $.mobile.activeBtnClass );
+ }
+ });
+
+ // Buttons in the navbar with ui-state-persist class should regain their active state before page show
+ $navbar.closest( ".ui-page" ).bind( "pagebeforeshow", function() {
+ $navbtns.filter( ".ui-state-persist" ).addClass( $.mobile.activeBtnClass );
+ });
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.navbar.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+//Keeps track of the number of lists per page UID
+//This allows support for multiple nested list in the same page
+//https://github.com/jquery/jquery-mobile/issues/1617
+var listCountPerPage = {};
+
+$.widget( "mobile.listview", $.mobile.widget, {
+
+ options: {
+ theme: null,
+ countTheme: "c",
+ headerTheme: "b",
+ dividerTheme: "b",
+ splitIcon: "arrow-r",
+ splitTheme: "b",
+ inset: false,
+ initSelector: ":jqmData(role='listview')"
+ },
+
+ _create: function() {
+ var t = this,
+ listviewClasses = "";
+
+ listviewClasses += t.options.inset ? " ui-listview-inset ui-corner-all ui-shadow " : "";
+
+ // create listview markup
+ t.element.addClass(function( i, orig ) {
+ return orig + " ui-listview " + listviewClasses;
+ });
+
+ t.refresh( true );
+ },
+
+ _removeCorners: function( li, which ) {
+ var top = "ui-corner-top ui-corner-tr ui-corner-tl",
+ bot = "ui-corner-bottom ui-corner-br ui-corner-bl";
+
+ li = li.add( li.find( ".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb" ) );
+
+ if ( which === "top" ) {
+ li.removeClass( top );
+ } else if ( which === "bottom" ) {
+ li.removeClass( bot );
+ } else {
+ li.removeClass( top + " " + bot );
+ }
+ },
+
+ _refreshCorners: function( create ) {
+ var $li,
+ $visibleli,
+ $topli,
+ $bottomli;
+
+ if ( this.options.inset ) {
+ $li = this.element.children( "li" );
+ // at create time the li are not visible yet so we need to rely on .ui-screen-hidden
+ $visibleli = create?$li.not( ".ui-screen-hidden" ):$li.filter( ":visible" );
+
+ this._removeCorners( $li );
+
+ // Select the first visible li element
+ $topli = $visibleli.first()
+ .addClass( "ui-corner-top" );
+
+ $topli.add( $topli.find( ".ui-btn-inner" )
+ .not( ".ui-li-link-alt span:first-child" ) )
+ .addClass( "ui-corner-top" )
+ .end()
+ .find( ".ui-li-link-alt, .ui-li-link-alt span:first-child" )
+ .addClass( "ui-corner-tr" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .not(".ui-li-icon")
+ .addClass( "ui-corner-tl" );
+
+ // Select the last visible li element
+ $bottomli = $visibleli.last()
+ .addClass( "ui-corner-bottom" );
+
+ $bottomli.add( $bottomli.find( ".ui-btn-inner" ) )
+ .find( ".ui-li-link-alt" )
+ .addClass( "ui-corner-br" )
+ .end()
+ .find( ".ui-li-thumb" )
+ .not(".ui-li-icon")
+ .addClass( "ui-corner-bl" );
+ }
+ if ( !create ) {
+ this.element.trigger( "updatelayout" );
+ }
+ },
+
+ // This is a generic utility method for finding the first
+ // node with a given nodeName. It uses basic DOM traversal
+ // to be fast and is meant to be a substitute for simple
+ // $.fn.closest() and $.fn.children() calls on a single
+ // element. Note that callers must pass both the lowerCase
+ // and upperCase version of the nodeName they are looking for.
+ // The main reason for this is that this function will be
+ // called many times and we want to avoid having to lowercase
+ // the nodeName from the element every time to ensure we have
+ // a match. Note that this function lives here for now, but may
+ // be moved into $.mobile if other components need a similar method.
+ _findFirstElementByTagName: function( ele, nextProp, lcName, ucName )
+ {
+ var dict = {};
+ dict[ lcName ] = dict[ ucName ] = true;
+ while ( ele ) {
+ if ( dict[ ele.nodeName ] ) {
+ return ele;
+ }
+ ele = ele[ nextProp ];
+ }
+ return null;
+ },
+ _getChildrenByTagName: function( ele, lcName, ucName )
+ {
+ var results = [],
+ dict = {};
+ dict[ lcName ] = dict[ ucName ] = true;
+ ele = ele.firstChild;
+ while ( ele ) {
+ if ( dict[ ele.nodeName ] ) {
+ results.push( ele );
+ }
+ ele = ele.nextSibling;
+ }
+ return $( results );
+ },
+
+ _addThumbClasses: function( containers )
+ {
+ var i, img, len = containers.length;
+ for ( i = 0; i < len; i++ ) {
+ img = $( this._findFirstElementByTagName( containers[ i ].firstChild, "nextSibling", "img", "IMG" ) );
+ if ( img.length ) {
+ img.addClass( "ui-li-thumb" );
+ $( this._findFirstElementByTagName( img[ 0 ].parentNode, "parentNode", "li", "LI" ) ).addClass( img.is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
+ }
+ }
+ },
+
+ refresh: function( create ) {
+ this.parentPage = this.element.closest( ".ui-page" );
+ this._createSubPages();
+
+ var o = this.options,
+ $list = this.element,
+ self = this,
+ dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
+ listsplittheme = $list.jqmData( "splittheme" ),
+ listspliticon = $list.jqmData( "spliticon" ),
+ li = this._getChildrenByTagName( $list[ 0 ], "li", "LI" ),
+ counter = $.support.cssPseudoElement || !$.nodeName( $list[ 0 ], "ol" ) ? 0 : 1,
+ itemClassDict = {},
+ item, itemClass, itemTheme,
+ a, last, splittheme, countParent, icon, imgParents, img, linkIcon;
+
+ if ( counter ) {
+ $list.find( ".ui-li-dec" ).remove();
+ }
+
+ if ( !o.theme ) {
+ o.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {
+ item = li.eq( pos );
+ itemClass = "ui-li";
+
+ // If we're creating the element, we update it regardless
+ if ( create || !item.hasClass( "ui-li" ) ) {
+ itemTheme = item.jqmData("theme") || o.theme;
+ a = this._getChildrenByTagName( item[ 0 ], "a", "A" );
+ var isDivider = ( item.jqmData( "role" ) === "list-divider" );
+
+ if ( a.length && !isDivider ) {
+ icon = item.jqmData("icon");
+
+ item.buttonMarkup({
+ wrapperEls: "div",
+ shadow: false,
+ corners: false,
+ iconpos: "right",
+ icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
+ theme: itemTheme
+ });
+
+ if ( ( icon != false ) && ( a.length == 1 ) ) {
+ item.addClass( "ui-li-has-arrow" );
+ }
+
+ a.first().removeClass( "ui-link" ).addClass( "ui-link-inherit" );
+
+ if ( a.length > 1 ) {
+ itemClass += " ui-li-has-alt";
+
+ last = a.last();
+ splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
+ linkIcon = last.jqmData("icon");
+
+ last.appendTo(item)
+ .attr( "title", last.getEncodedText() )
+ .addClass( "ui-li-link-alt" )
+ .empty()
+ .buttonMarkup({
+ shadow: false,
+ corners: false,
+ theme: itemTheme,
+ icon: false,
+ iconpos: "notext"
+ })
+ .find( ".ui-btn-inner" )
+ .append(
+ $( document.createElement( "span" ) ).buttonMarkup({
+ shadow: true,
+ corners: true,
+ theme: splittheme,
+ iconpos: "notext",
+ // link icon overrides list item icon overrides ul element overrides options
+ icon: linkIcon || icon || listspliticon || o.splitIcon
+ })
+ );
+ }
+ } else if ( isDivider ) {
+
+ itemClass += " ui-li-divider ui-bar-" + dividertheme;
+ item.attr( "role", "heading" );
+
+ //reset counter when a divider heading is encountered
+ if ( counter ) {
+ counter = 1;
+ }
+
+ } else {
+ itemClass += " ui-li-static ui-body-" + itemTheme;
+ }
+ }
+
+ if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
+ countParent = item.is( ".ui-li-static:first" ) ? item : item.find( ".ui-link-inherit" );
+
+ countParent.addClass( "ui-li-jsnumbering" )
+ .prepend( "<span class='ui-li-dec'>" + (counter++) + ". </span>" );
+ }
+
+ // Instead of setting item class directly on the list item and its
+ // btn-inner at this point in time, push the item into a dictionary
+ // that tells us what class to set on it so we can do this after this
+ // processing loop is finished.
+
+ if ( !itemClassDict[ itemClass ] ) {
+ itemClassDict[ itemClass ] = [];
+ }
+
+ itemClassDict[ itemClass ].push( item[ 0 ] );
+ }
+
+ // Set the appropriate listview item classes on each list item
+ // and their btn-inner elements. The main reason we didn't do this
+ // in the for-loop above is because we can eliminate per-item function overhead
+ // by calling addClass() and children() once or twice afterwards. This
+ // can give us a significant boost on platforms like WP7.5.
+
+ for ( itemClass in itemClassDict ) {
+ $( itemClassDict[ itemClass ] ).addClass( itemClass ).children( ".ui-btn-inner" ).addClass( itemClass );
+ }
+
+ $list.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" )
+ .end()
+
+ .find( "p, dl" ).addClass( "ui-li-desc" )
+ .end()
+
+ .find( ".ui-li-aside" ).each(function() {
+ var $this = $(this);
+ $this.prependTo( $this.parent() ); //shift aside to front for css float
+ })
+ .end()
+
+ .find( ".ui-li-count" ).each( function() {
+ $( this ).closest( "li" ).addClass( "ui-li-has-count" );
+ }).addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );
+
+ // The idea here is to look at the first image in the list item
+ // itself, and any .ui-link-inherit element it may contain, so we
+ // can place the appropriate classes on the image and list item.
+ // Note that we used to use something like:
+ //
+ // li.find(">img:eq(0), .ui-link-inherit>img:eq(0)").each( ... );
+ //
+ // But executing a find() like that on Windows Phone 7.5 took a
+ // really long time. Walking things manually with the code below
+ // allows the 400 listview item page to load in about 3 seconds as
+ // opposed to 30 seconds.
+
+ this._addThumbClasses( li );
+ this._addThumbClasses( $list.find( ".ui-link-inherit" ) );
+
+ this._refreshCorners( create );
+ },
+
+ //create a string for ID/subpage url creation
+ _idStringEscape: function( str ) {
+ return str.replace(/[^a-zA-Z0-9]/g, '-');
+ },
+
+ _createSubPages: function() {
+ var parentList = this.element,
+ parentPage = parentList.closest( ".ui-page" ),
+ parentUrl = parentPage.jqmData( "url" ),
+ parentId = parentUrl || parentPage[ 0 ][ $.expando ],
+ parentListId = parentList.attr( "id" ),
+ o = this.options,
+ dns = "data-" + $.mobile.ns,
+ self = this,
+ persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
+ hasSubPages;
+
+ if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
+ listCountPerPage[ parentId ] = -1;
+ }
+
+ parentListId = parentListId || ++listCountPerPage[ parentId ];
+
+ $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
+ var self = this,
+ list = $( this ),
+ listId = list.attr( "id" ) || parentListId + "-" + i,
+ parent = list.parent(),
+ nodeEls = $( list.prevAll().toArray().reverse() ),
+ nodeEls = nodeEls.length ? nodeEls : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
+ title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
+ id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
+ theme = list.jqmData( "theme" ) || o.theme,
+ countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
+ newPage, anchor;
+
+ //define hasSubPages for use in later removal
+ hasSubPages = true;
+
+ newPage = list.detach()
+ .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
+ .parent()
+ .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
+ .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>") : "" )
+ .parent()
+ .appendTo( $.mobile.pageContainer );
+
+ newPage.page();
+
+ anchor = parent.find('a:first');
+
+ if ( !anchor.length ) {
+ anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
+ }
+
+ anchor.attr( "href", "#" + id );
+
+ }).listview();
+
+ // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
+ // and aren't embedded
+ if( hasSubPages &&
+ parentPage.is( ":jqmData(external-page='true')" ) &&
+ parentPage.data("page").options.domCache === false ) {
+
+ var newRemove = function( e, ui ){
+ var nextPage = ui.nextPage, npURL,
+ prEvent = new $.Event( "pageremove" );
+
+ if( ui.nextPage ){
+ npURL = nextPage.jqmData( "url" );
+ if( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ){
+ self.childPages().remove();
+ parentPage.trigger( prEvent );
+ if( !prEvent.isDefaultPrevented() ){
+ parentPage.removeWithDependents();
+ }
+ }
+ }
+ };
+
+ // unbind the original page remove and replace with our specialized version
+ parentPage
+ .unbind( "pagehide.remove" )
+ .bind( "pagehide.remove", newRemove);
+ }
+ },
+
+ // TODO sort out a better way to track sub pages of the listview this is brittle
+ childPages: function(){
+ var parentUrl = this.parentPage.jqmData( "url" );
+
+ return $( ":jqmData(url^='"+ parentUrl + "&" + $.mobile.subPageUrlKey +"')");
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.listview.prototype.enhanceWithin( e.target );
+});
+
+})( jQuery );
+
+/*
+* "checkboxradio" plugin
+*/
+
+(function( $, undefined ) {
+
+$.widget( "mobile.checkboxradio", $.mobile.widget, {
+ options: {
+ theme: null,
+ initSelector: "input[type='checkbox'],input[type='radio']"
+ },
+ _create: function() {
+ var self = this,
+ input = this.element,
+ inheritAttr = function( input, dataAttr ) {
+ return input.jqmData( dataAttr ) || input.closest( "form,fieldset" ).jqmData( dataAttr )
+ },
+ // NOTE: Windows Phone could not find the label through a selector
+ // filter works though.
+ parentLabel = $( input ).closest( "label" ),
+ label = parentLabel.length ? parentLabel : $( input ).closest( "form,fieldset,:jqmData(role='page'),:jqmData(role='dialog')" ).find( "label" ).filter( "[for='" + input[0].id + "']" ),
+ inputtype = input[0].type,
+ mini = inheritAttr( input, "mini" ),
+ checkedState = inputtype + "-on",
+ uncheckedState = inputtype + "-off",
+ icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
+ iconpos = inheritAttr( input, "iconpos" ),
+ activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
+ checkedClass = "ui-" + checkedState + activeBtn,
+ uncheckedClass = "ui-" + uncheckedState,
+ checkedicon = "ui-icon-" + checkedState,
+ uncheckedicon = "ui-icon-" + uncheckedState;
+
+ if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
+ return;
+ }
+
+ // Expose for other methods
+ $.extend( this, {
+ label: label,
+ inputtype: inputtype,
+ checkedClass: checkedClass,
+ uncheckedClass: uncheckedClass,
+ checkedicon: checkedicon,
+ uncheckedicon: uncheckedicon
+ });
+
+ // If there's no selected theme check the data attr
+ if( !this.options.theme ) {
+ this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ label.buttonMarkup({
+ theme: this.options.theme,
+ icon: icon,
+ shadow: false,
+ mini: mini,
+ iconpos: iconpos
+ });
+
+ // Wrap the input + label in a div
+ var wrapper = document.createElement('div');
+ wrapper.className = 'ui-' + inputtype;
+
+ input.add( label ).wrapAll( wrapper );
+
+ label.bind({
+ vmouseover: function( event ) {
+ if ( $( this ).parent().is( ".ui-disabled" ) ) {
+ event.stopPropagation();
+ }
+ },
+
+ vclick: function( event ) {
+ if ( input.is( ":disabled" ) ) {
+ event.preventDefault();
+ return;
+ }
+
+ self._cacheVals();
+
+ input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
+
+ // trigger click handler's bound directly to the input as a substitute for
+ // how label clicks behave normally in the browsers
+ // TODO: it would be nice to let the browser's handle the clicks and pass them
+ // through to the associate input. we can swallow that click at the parent
+ // wrapper element level
+ input.triggerHandler( 'click' );
+
+ // Input set for common radio buttons will contain all the radio
+ // buttons, but will not for checkboxes. clearing the checked status
+ // of other radios ensures the active button state is applied properly
+ self._getInputSet().not( input ).prop( "checked", false );
+
+ self._updateAll();
+ return false;
+ }
+ });
+
+ input
+ .bind({
+ vmousedown: function() {
+ self._cacheVals();
+ },
+
+ vclick: function() {
+ var $this = $(this);
+
+ // Adds checked attribute to checked input when keyboard is used
+ if ( $this.is( ":checked" ) ) {
+
+ $this.prop( "checked", true);
+ self._getInputSet().not($this).prop( "checked", false );
+ } else {
+
+ $this.prop( "checked", false );
+ }
+
+ self._updateAll();
+ },
+
+ focus: function() {
+ label.addClass( $.mobile.focusClass );
+ },
+
+ blur: function() {
+ label.removeClass( $.mobile.focusClass );
+ }
+ });
+
+ this.refresh();
+ },
+
+ _cacheVals: function() {
+ this._getInputSet().each(function() {
+ $(this).jqmData( "cacheVal", this.checked );
+ });
+ },
+
+ //returns either a set of radios with the same name attribute, or a single checkbox
+ _getInputSet: function(){
+ if(this.inputtype === "checkbox") {
+ return this.element;
+ }
+
+ return this.element.closest( "form,fieldset,:jqmData(role='page')" )
+ .find( "input[name='"+ this.element[0].name +"'][type='"+ this.inputtype +"']" );
+ },
+
+ _updateAll: function() {
+ var self = this;
+
+ this._getInputSet().each(function() {
+ var $this = $(this);
+
+ if ( this.checked || self.inputtype === "checkbox" ) {
+ $this.trigger( "change" );
+ }
+ })
+ .checkboxradio( "refresh" );
+ },
+
+ refresh: function() {
+ var input = this.element[0],
+ label = this.label,
+ icon = label.find( ".ui-icon" );
+
+ if ( input.checked ) {
+ label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
+ icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
+ } else {
+ label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
+ icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
+ }
+
+ if ( input.disabled ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+ },
+
+ disable: function() {
+ this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
+ },
+
+ enable: function() {
+ this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.button", $.mobile.widget, {
+ options: {
+ theme: null,
+ icon: null,
+ iconpos: null,
+ inline: false,
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ initSelector: "button, [type='button'], [type='submit'], [type='reset'], [type='image']",
+ mini: false
+ },
+ _create: function() {
+ var $el = this.element,
+ $button,
+ o = this.options,
+ type,
+ name,
+ classes = "",
+ $buttonPlaceholder;
+
+ // if this is a link, check if it's been enhanced and, if not, use the right function
+ if( $el[ 0 ].tagName === "A" ) {
+ !$el.hasClass( "ui-btn" ) && $el.buttonMarkup();
+ return;
+ }
+
+ // get the inherited theme
+ // TODO centralize for all widgets
+ if ( !this.options.theme ) {
+ this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
+ }
+
+ // TODO: Post 1.1--once we have time to test thoroughly--any classes manually applied to the original element should be carried over to the enhanced element, with an `-enhanced` suffix. See https://github.com/jquery/jquery-mobile/issues/3577
+ /* if( $el[0].className.length ) {
+ classes = $el[0].className;
+ } */
+ if( !!~$el[0].className.indexOf( "ui-btn-left" ) ) {
+ classes = "ui-btn-left";
+ }
+
+ if( !!~$el[0].className.indexOf( "ui-btn-right" ) ) {
+ classes = "ui-btn-right";
+ }
+
+ if( $el.attr( "type" ) === "submit" || $el.attr( "type" ) === "reset" ) {
+ classes ? classes += " ui-submit" : classes = "ui-submit";
+ }
+
+ $( "label[for='" + $el.attr( "id" ) + "']" ).addClass( "ui-submit" );
+
+ // Add ARIA role
+ this.button = $( "<div></div>" )
+ .text( $el.text() || $el.val() )
+ .insertBefore( $el )
+ .buttonMarkup({
+ theme: o.theme,
+ icon: o.icon,
+ iconpos: o.iconpos,
+ inline: o.inline,
+ corners: o.corners,
+ shadow: o.shadow,
+ iconshadow: o.iconshadow,
+ mini: o.mini
+ })
+ .addClass( classes )
+ .append( $el.addClass( "ui-btn-hidden" ) );
+
+ $button = this.button;
+ type = $el.attr( "type" );
+ name = $el.attr( "name" );
+
+ // Add hidden input during submit if input type="submit" has a name.
+ if ( type !== "button" && type !== "reset" && name ) {
+ $el.bind( "vclick", function() {
+ // Add hidden input if it doesn't already exist.
+ if( $buttonPlaceholder === undefined ) {
+ $buttonPlaceholder = $( "<input>", {
+ type: "hidden",
+ name: $el.attr( "name" ),
+ value: $el.attr( "value" )
+ }).insertBefore( $el );
+
+ // Bind to doc to remove after submit handling
+ $( document ).one("submit", function(){
+ $buttonPlaceholder.remove();
+
+ // reset the local var so that the hidden input
+ // will be re-added on subsequent clicks
+ $buttonPlaceholder = undefined;
+ });
+ }
+ });
+ }
+
+ $el.bind({
+ focus: function() {
+ $button.addClass( $.mobile.focusClass );
+ },
+
+ blur: function() {
+ $button.removeClass( $.mobile.focusClass );
+ }
+ });
+
+ this.refresh();
+ },
+
+ enable: function() {
+ this.element.attr( "disabled", false );
+ this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
+ return this._setOption( "disabled", false );
+ },
+
+ disable: function() {
+ this.element.attr( "disabled", true );
+ this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
+ return this._setOption( "disabled", true );
+ },
+
+ refresh: function() {
+ var $el = this.element;
+
+ if ( $el.prop("disabled") ) {
+ this.disable();
+ } else {
+ this.enable();
+ }
+
+ // Grab the button's text element from its implementation-independent data item
+ $( this.button.data( 'buttonElements' ).text ).text( $el.text() || $el.val() );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.button.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.fn.controlgroup = function( options ) {
+ function flipClasses( els, flCorners ) {
+ els.removeClass( "ui-btn-corner-all ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-controlgroup-last ui-shadow" )
+ .eq( 0 ).addClass( flCorners[ 0 ] )
+ .end()
+ .last().addClass( flCorners[ 1 ] ).addClass( "ui-controlgroup-last" );
+ }
+
+ return this.each(function() {
+ var $el = $( this ),
+ o = $.extend({
+ direction: $el.jqmData( "type" ) || "vertical",
+ shadow: false,
+ excludeInvisible: true,
+ mini: $el.jqmData( "mini" )
+ }, options ),
+ groupheading = $el.children( "legend" ),
+ flCorners = o.direction == "horizontal" ? [ "ui-corner-left", "ui-corner-right" ] : [ "ui-corner-top", "ui-corner-bottom" ],
+ type = $el.find( "input" ).first().attr( "type" );
+
+ $el.wrapInner( "<div class='ui-controlgroup-controls'></div>" );
+
+ // Replace legend with more stylable replacement div
+ if ( groupheading.length ) {
+ $( "<div role='heading' class='ui-controlgroup-label'>" + groupheading.html() + "</div>" ).insertBefore( $el.children(0) );
+ groupheading.remove();
+ }
+
+ $el.addClass( "ui-corner-all ui-controlgroup ui-controlgroup-" + o.direction );
+
+ flipClasses( $el.find( ".ui-btn" + ( o.excludeInvisible ? ":visible" : "" ) ).not('.ui-slider-handle'), flCorners );
+ flipClasses( $el.find( ".ui-btn-inner" ), flCorners );
+
+ if ( o.shadow ) {
+ $el.addClass( "ui-shadow" );
+ }
+
+ if ( o.mini ) {
+ $el.addClass( "ui-mini" );
+ }
+
+ });
+};
+
+// The pagecreate handler for controlgroup is in jquery.mobile.init because of the soft-dependency on the wrapped widgets
+
+})(jQuery);
+
+(function( $, undefined ) {
+
+$( document ).bind( "pagecreate create", function( e ){
+
+ //links within content areas, tests included with page
+ $( e.target )
+ .find( "a" )
+ .jqmEnhanceable()
+ .not( ".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')" )
+ .addClass( "ui-link" );
+
+});
+
+})( jQuery );
+
+
+( function( $ ) {
+ var meta = $( "meta[name=viewport]" ),
+ initialContent = meta.attr( "content" ),
+ disabledZoom = initialContent + ",maximum-scale=1, user-scalable=no",
+ enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes",
+ disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test( initialContent );
+
+ $.mobile.zoom = $.extend( {}, {
+ enabled: !disabledInitially,
+ locked: false,
+ disable: function( lock ) {
+ if( !disabledInitially && !$.mobile.zoom.locked ){
+ meta.attr( "content", disabledZoom );
+ $.mobile.zoom.enabled = false;
+ $.mobile.zoom.locked = lock || false;
+ }
+ },
+ enable: function( unlock ) {
+ if( !disabledInitially && ( !$.mobile.zoom.locked || unlock === true ) ){
+ meta.attr( "content", enabledZoom );
+ $.mobile.zoom.enabled = true;
+ $.mobile.zoom.locked = false;
+ }
+ },
+ restore: function() {
+ if( !disabledInitially ){
+ meta.attr( "content", initialContent );
+ $.mobile.zoom.enabled = true;
+ }
+ }
+ });
+
+}( jQuery ));
+
+(function( $, undefined ) {
+
+$.widget( "mobile.textinput", $.mobile.widget, {
+ options: {
+ theme: null,
+ // This option defaults to true on iOS devices.
+ preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
+ initSelector: "input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type])",
+ clearSearchButtonText: "clear text"
+ },
+
+ _create: function() {
+
+ var input = this.element,
+ o = this.options,
+ theme = o.theme || $.mobile.getInheritedTheme( this.element, "c" ),
+ themeclass = " ui-body-" + theme,
+ mini = input.jqmData("mini") == true,
+ miniclass = mini ? " ui-mini" : "",
+ focusedEl, clearbtn;
+
+ $( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );
+
+ focusedEl = input.addClass("ui-input-text ui-body-"+ theme );
+
+ // XXX: Temporary workaround for issue 785 (Apple bug 8910589).
+ // Turn off autocorrect and autocomplete on non-iOS 5 devices
+ // since the popup they use can't be dismissed by the user. Note
+ // that we test for the presence of the feature by looking for
+ // the autocorrect property on the input element. We currently
+ // have no test for iOS 5 or newer so we're temporarily using
+ // the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
+ if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
+ // Set the attribute instead of the property just in case there
+ // is code that attempts to make modifications via HTML.
+ input[0].setAttribute( "autocorrect", "off" );
+ input[0].setAttribute( "autocomplete", "off" );
+ }
+
+
+ //"search" input widget
+ if ( input.is( "[type='search'],:jqmData(type='search')" ) ) {
+
+ focusedEl = input.wrap( "<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield" + themeclass + miniclass + "'></div>" ).parent();
+ clearbtn = $( "<a href='#' class='ui-input-clear' title='" + o.clearSearchButtonText + "'>" + o.clearSearchButtonText + "</a>" )
+ .bind('click', function( event ) {
+ input
+ .val( "" )
+ .focus()
+ .trigger( "change" );
+ clearbtn.addClass( "ui-input-clear-hidden" );
+ event.preventDefault();
+ })
+ .appendTo( focusedEl )
+ .buttonMarkup({
+ icon: "delete",
+ iconpos: "notext",
+ corners: true,
+ shadow: true,
+ mini: mini
+ });
+
+ function toggleClear() {
+ setTimeout(function() {
+ clearbtn.toggleClass( "ui-input-clear-hidden", !input.val() );
+ }, 0);
+ }
+
+ toggleClear();
+
+ input.bind('paste cut keyup focus change blur', toggleClear);
+
+ } else {
+ input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
+ }
+
+ input.focus(function() {
+ focusedEl.addClass( $.mobile.focusClass );
+ })
+ .blur(function(){
+ focusedEl.removeClass( $.mobile.focusClass );
+ })
+ // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
+ .bind( "focus", function() {
+ if( o.preventFocusZoom ){
+ $.mobile.zoom.disable( true );
+ }
+ })
+ .bind( "blur", function() {
+ if( o.preventFocusZoom ){
+ $.mobile.zoom.enable( true );
+ }
+ });
+
+ // Autogrow
+ if ( input.is( "textarea" ) ) {
+ var extraLineHeight = 15,
+ keyupTimeoutBuffer = 100,
+ keyup = function() {
+ var scrollHeight = input[ 0 ].scrollHeight,
+ clientHeight = input[ 0 ].clientHeight;
+
+ if ( clientHeight < scrollHeight ) {
+ input.height(scrollHeight + extraLineHeight);
+ }
+ },
+ keyupTimeout;
+
+ input.keyup(function() {
+ clearTimeout( keyupTimeout );
+ keyupTimeout = setTimeout( keyup, keyupTimeoutBuffer );
+ });
+
+ // binding to pagechange here ensures that for pages loaded via
+ // ajax the height is recalculated without user input
+ $( document ).one( "pagechange", keyup );
+
+ // Issue 509: the browser is not providing scrollHeight properly until the styles load
+ if ( $.trim( input.val() ) ) {
+ // bind to the window load to make sure the height is calculated based on BOTH
+ // the DOM and CSS
+ $( window ).load( keyup );
+ }
+ }
+ },
+
+ disable: function(){
+ ( this.element.attr( "disabled", true ).is( "[type='search'],:jqmData(type='search')" ) ?
+ this.element.parent() : this.element ).addClass( "ui-disabled" );
+ },
+
+ enable: function(){
+ ( this.element.attr( "disabled", false).is( "[type='search'],:jqmData(type='search')" ) ?
+ this.element.parent() : this.element ).removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.textinput.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.mobile.listview.prototype.options.filter = false;
+$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
+$.mobile.listview.prototype.options.filterTheme = "c";
+$.mobile.listview.prototype.options.filterCallback = function( text, searchValue ){
+ return text.toLowerCase().indexOf( searchValue ) === -1;
+};
+
+$( document ).delegate( ":jqmData(role='listview')", "listviewcreate", function() {
+
+ var list = $( this ),
+ listview = list.data( "listview" );
+
+ if ( !listview.options.filter ) {
+ return;
+ }
+
+ var wrapper = $( "<form>", {
+ "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme,
+ "role": "search"
+ }),
+ search = $( "<input>", {
+ placeholder: listview.options.filterPlaceholder
+ })
+ .attr( "data-" + $.mobile.ns + "type", "search" )
+ .jqmData( "lastval", "" )
+ .bind( "keyup change", function() {
+
+ var $this = $(this),
+ val = this.value.toLowerCase(),
+ listItems = null,
+ lastval = $this.jqmData( "lastval" ) + "",
+ childItems = false,
+ itemtext = "",
+ item;
+
+ // Change val as lastval for next execution
+ $this.jqmData( "lastval" , val );
+ if ( val.length < lastval.length || val.indexOf(lastval) !== 0 ) {
+
+ // Removed chars or pasted something totally different, check all items
+ listItems = list.children();
+ } else {
+
+ // Only chars added, not removed, only use visible subset
+ listItems = list.children( ":not(.ui-screen-hidden)" );
+ }
+
+ if ( val ) {
+
+ // This handles hiding regular rows without the text we search for
+ // and any list dividers without regular rows shown under it
+
+ for ( var i = listItems.length - 1; i >= 0; i-- ) {
+ item = $( listItems[ i ] );
+ itemtext = item.jqmData( "filtertext" ) || item.text();
+
+ if ( item.is( "li:jqmData(role=list-divider)" ) ) {
+
+ item.toggleClass( "ui-filter-hidequeue" , !childItems );
+
+ // New bucket!
+ childItems = false;
+
+ } else if ( listview.options.filterCallback( itemtext, val ) ) {
+
+ //mark to be hidden
+ item.toggleClass( "ui-filter-hidequeue" , true );
+ } else {
+
+ // There's a shown item in the bucket
+ childItems = true;
+ }
+ }
+
+ // Show items, not marked to be hidden
+ listItems
+ .filter( ":not(.ui-filter-hidequeue)" )
+ .toggleClass( "ui-screen-hidden", false );
+
+ // Hide items, marked to be hidden
+ listItems
+ .filter( ".ui-filter-hidequeue" )
+ .toggleClass( "ui-screen-hidden", true )
+ .toggleClass( "ui-filter-hidequeue", false );
+
+ } else {
+
+ //filtervalue is empty => show all
+ listItems.toggleClass( "ui-screen-hidden", false );
+ }
+ listview._refreshCorners();
+ })
+ .appendTo( wrapper )
+ .textinput();
+
+ if ( listview.options.inset ) {
+ wrapper.addClass( "ui-listview-filter-inset" );
+ }
+
+ wrapper.bind( "submit", function() {
+ return false;
+ })
+ .insertBefore( list );
+});
+
+})( jQuery );
+
+( function( $, undefined ) {
+
+$.widget( "mobile.slider", $.mobile.widget, {
+ options: {
+ theme: null,
+ trackTheme: null,
+ disabled: false,
+ initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",
+ mini: false
+ },
+
+ _create: function() {
+
+ // TODO: Each of these should have comments explain what they're for
+ var self = this,
+
+ control = this.element,
+
+ parentTheme = $.mobile.getInheritedTheme( control, "c" ),
+
+ theme = this.options.theme || parentTheme,
+
+ trackTheme = this.options.trackTheme || parentTheme,
+
+ cType = control[ 0 ].nodeName.toLowerCase(),
+
+ selectClass = ( cType == "select" ) ? "ui-slider-switch" : "",
+
+ controlID = control.attr( "id" ),
+
+ $label = $( "[for='" + controlID + "']" ),
+
+ labelID = $label.attr( "id" ) || controlID + "-label",
+
+ label = $label.attr( "id", labelID ),
+
+ val = function() {
+ return cType == "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
+ },
+
+ min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0,
+
+ max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
+
+ step = window.parseFloat( control.attr( "step" ) || 1 ),
+
+ inlineClass = ( this.options.inline || control.jqmData("inline") == true ) ? " ui-slider-inline" : "",
+
+ miniClass = ( this.options.mini || control.jqmData("mini") ) ? " ui-slider-mini" : "",
+
+
+ domHandle = document.createElement('a'),
+ handle = $( domHandle ),
+ domSlider = document.createElement('div'),
+ slider = $( domSlider ),
+
+ valuebg = control.jqmData("highlight") && cType != "select" ? (function() {
+ var bg = document.createElement('div');
+ bg.className = 'ui-slider-bg ' + $.mobile.activeBtnClass + ' ui-btn-corner-all';
+ return $( bg ).prependTo( slider );
+ })() : false,
+
+ options;
+
+ domHandle.setAttribute( 'href', "#" );
+ domSlider.setAttribute('role','application');
+ domSlider.className = ['ui-slider ',selectClass," ui-btn-down-",trackTheme,' ui-btn-corner-all', inlineClass, miniClass].join("");
+ domHandle.className = 'ui-slider-handle';
+ domSlider.appendChild(domHandle);
+
+ handle.buttonMarkup({ corners: true, theme: theme, shadow: true })
+ .attr({
+ "role": "slider",
+ "aria-valuemin": min,
+ "aria-valuemax": max,
+ "aria-valuenow": val(),
+ "aria-valuetext": val(),
+ "title": val(),
+ "aria-labelledby": labelID
+ });
+
+ $.extend( this, {
+ slider: slider,
+ handle: handle,
+ valuebg: valuebg,
+ dragging: false,
+ beforeStart: null,
+ userModified: false,
+ mouseMoved: false
+ });
+
+ if ( cType == "select" ) {
+ var wrapper = document.createElement('div');
+ wrapper.className = 'ui-slider-inneroffset';
+
+ for(var j = 0,length = domSlider.childNodes.length;j < length;j++){
+ wrapper.appendChild(domSlider.childNodes[j]);
+ }
+
+ domSlider.appendChild(wrapper);
+
+ // slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
+
+ // make the handle move with a smooth transition
+ handle.addClass( "ui-slider-handle-snapping" );
+
+ options = control.find( "option" );
+
+ for(var i = 0, optionsCount = options.length; i < optionsCount; i++){
+ var side = !i ? "b":"a",
+ sliderTheme = !i ? " ui-btn-down-" + trackTheme :( " " + $.mobile.activeBtnClass ),
+ sliderLabel = document.createElement('div'),
+ sliderImg = document.createElement('span');
+
+ sliderImg.className = ['ui-slider-label ui-slider-label-',side,sliderTheme," ui-btn-corner-all"].join("");
+ sliderImg.setAttribute('role','img');
+ sliderImg.appendChild(document.createTextNode(options[i].innerHTML));
+ $(sliderImg).prependTo( slider );
+ }
+
+ self._labels = $( ".ui-slider-label", slider );
+
+ }
+
+ label.addClass( "ui-slider" );
+
+ // monitor the input for updated values
+ control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" )
+ .change( function() {
+ // if the user dragged the handle, the "change" event was triggered from inside refresh(); don't call refresh() again
+ if (!self.mouseMoved) {
+ self.refresh( val(), true );
+ }
+ })
+ .keyup( function() { // necessary?
+ self.refresh( val(), true, true );
+ })
+ .blur( function() {
+ self.refresh( val(), true );
+ });
+
+ // prevent screen drag when slider activated
+ $( document ).bind( "vmousemove", function( event ) {
+ if ( self.dragging ) {
+ // self.mouseMoved must be updated before refresh() because it will be used in the control "change" event
+ self.mouseMoved = true;
+
+ if ( cType === "select" ) {
+ // make the handle move in sync with the mouse
+ handle.removeClass( "ui-slider-handle-snapping" );
+ }
+
+ self.refresh( event );
+
+ // only after refresh() you can calculate self.userModified
+ self.userModified = self.beforeStart !== control[0].selectedIndex;
+ return false;
+ }
+ });
+
+ slider.bind( "vmousedown", function( event ) {
+ self.dragging = true;
+ self.userModified = false;
+ self.mouseMoved = false;
+
+ if ( cType === "select" ) {
+ self.beforeStart = control[0].selectedIndex;
+ }
+
+ self.refresh( event );
+ return false;
+ })
+ .bind( "vclick", false );
+
+ slider.add( document )
+ .bind( "vmouseup", function() {
+ if ( self.dragging ) {
+
+ self.dragging = false;
+
+ if ( cType === "select") {
+
+ // make the handle move with a smooth transition
+ handle.addClass( "ui-slider-handle-snapping" );
+
+ if ( self.mouseMoved ) {
+
+ // this is a drag, change the value only if user dragged enough
+ if ( self.userModified ) {
+ self.refresh( self.beforeStart == 0 ? 1 : 0 );
+ }
+ else {
+ self.refresh( self.beforeStart );
+ }
+
+ }
+ else {
+ // this is just a click, change the value
+ self.refresh( self.beforeStart == 0 ? 1 : 0 );
+ }
+
+ }
+
+ self.mouseMoved = false;
+
+ return false;
+ }
+ });
+
+ slider.insertAfter( control );
+
+ // Only add focus class to toggle switch, sliders get it automatically from ui-btn
+ if( cType == 'select' ) {
+ this.handle.bind({
+ focus: function() {
+ slider.addClass( $.mobile.focusClass );
+ },
+
+ blur: function() {
+ slider.removeClass( $.mobile.focusClass );
+ }
+ });
+ }
+
+ this.handle.bind({
+ // NOTE force focus on handle
+ vmousedown: function() {
+ $( this ).focus();
+ },
+
+ vclick: false,
+
+ keydown: function( event ) {
+ var index = val();
+
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ // In all cases prevent the default and mark the handle as active
+ switch ( event.keyCode ) {
+ case $.mobile.keyCode.HOME:
+ case $.mobile.keyCode.END:
+ case $.mobile.keyCode.PAGE_UP:
+ case $.mobile.keyCode.PAGE_DOWN:
+ case $.mobile.keyCode.UP:
+ case $.mobile.keyCode.RIGHT:
+ case $.mobile.keyCode.DOWN:
+ case $.mobile.keyCode.LEFT:
+ event.preventDefault();
+
+ if ( !self._keySliding ) {
+ self._keySliding = true;
+ $( this ).addClass( "ui-state-active" );
+ }
+ break;
+ }
+
+ // move the slider according to the keypress
+ switch ( event.keyCode ) {
+ case $.mobile.keyCode.HOME:
+ self.refresh( min );
+ break;
+ case $.mobile.keyCode.END:
+ self.refresh( max );
+ break;
+ case $.mobile.keyCode.PAGE_UP:
+ case $.mobile.keyCode.UP:
+ case $.mobile.keyCode.RIGHT:
+ self.refresh( index + step );
+ break;
+ case $.mobile.keyCode.PAGE_DOWN:
+ case $.mobile.keyCode.DOWN:
+ case $.mobile.keyCode.LEFT:
+ self.refresh( index - step );
+ break;
+ }
+ }, // remove active mark
+
+ keyup: function( event ) {
+ if ( self._keySliding ) {
+ self._keySliding = false;
+ $( this ).removeClass( "ui-state-active" );
+ }
+ }
+ });
+
+ this.refresh(undefined, undefined, true);
+ },
+
+ refresh: function( val, isfromControl, preventInputUpdate ) {
+
+ if ( this.options.disabled || this.element.attr('disabled')) {
+ this.disable();
+ }
+
+ var control = this.element, percent,
+ cType = control[0].nodeName.toLowerCase(),
+ min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0,
+ max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1,
+ step = (cType === "input" && parseFloat( control.attr( "step" ) ) > 0) ? parseFloat(control.attr("step")) : 1;
+
+ if ( typeof val === "object" ) {
+ var data = val,
+ // a slight tolerance helped get to the ends of the slider
+ tol = 8;
+ if ( !this.dragging ||
+ data.pageX < this.slider.offset().left - tol ||
+ data.pageX > this.slider.offset().left + this.slider.width() + tol ) {
+ return;
+ }
+ percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 );
+ } else {
+ if ( val == null ) {
+ val = cType === "input" ? parseFloat( control.val() || 0 ) : control[0].selectedIndex;
+ }
+ percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
+ }
+
+ if ( isNaN( percent ) ) {
+ return;
+ }
+
+ if ( percent < 0 ) {
+ percent = 0;
+ }
+
+ if ( percent > 100 ) {
+ percent = 100;
+ }
+
+ var newval = ( percent / 100 ) * ( max - min ) + min;
+
+ //from jQuery UI slider, the following source will round to the nearest step
+ var valModStep = ( newval - min ) % step;
+ var alignValue = newval - valModStep;
+
+ if ( Math.abs( valModStep ) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see jQueryUI: #4124)
+ newval = parseFloat( alignValue.toFixed(5) );
+
+ if ( newval < min ) {
+ newval = min;
+ }
+
+ if ( newval > max ) {
+ newval = max;
+ }
+
+ this.handle.css( "left", percent + "%" );
+ this.handle.attr( {
+ "aria-valuenow": cType === "input" ? newval : control.find( "option" ).eq( newval ).attr( "value" ),
+ "aria-valuetext": cType === "input" ? newval : control.find( "option" ).eq( newval ).getEncodedText(),
+ title: cType === "input" ? newval : control.find( "option" ).eq( newval ).getEncodedText()
+ });
+ this.valuebg && this.valuebg.css( "width", percent + "%" );
+
+ // drag the label widths
+ if ( this._labels ) {
+ var handlePercent = this.handle.width() / this.slider.width() * 100,
+ aPercent = percent && handlePercent + ( 100 - handlePercent ) * percent / 100,
+ bPercent = percent === 100 ? 0 : Math.min( handlePercent + 100 - aPercent, 100 );
+
+ this._labels.each(function(){
+ var ab = $(this).is( ".ui-slider-label-a" );
+ $( this ).width( ( ab ? aPercent : bPercent ) + "%" );
+ });
+ }
+
+ if ( !preventInputUpdate ) {
+ var valueChanged = false;
+
+ // update control"s value
+ if ( cType === "input" ) {
+ valueChanged = control.val() !== newval;
+ control.val( newval );
+ } else {
+ valueChanged = control[ 0 ].selectedIndex !== newval;
+ control[ 0 ].selectedIndex = newval;
+ }
+ if ( !isfromControl && valueChanged ) {
+ control.trigger( "change" );
+ }
+ }
+ },
+
+ enable: function() {
+ this.element.attr( "disabled", false );
+ this.slider.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
+ return this._setOption( "disabled", false );
+ },
+
+ disable: function() {
+ this.element.attr( "disabled", true );
+ this.slider.addClass( "ui-disabled" ).attr( "aria-disabled", true );
+ return this._setOption( "disabled", true );
+ }
+
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.slider.prototype.enhanceWithin( e.target, true );
+});
+
+})( jQuery );
+
+(function( $, undefined ) {
+
+$.widget( "mobile.selectmenu", $.mobile.widget, {
+ options: {
+ theme: null,
+ disabled: false,
+ icon: "arrow-d",
+ iconpos: "right",
+ inline: false,
+ corners: true,
+ shadow: true,
+ iconshadow: true,
+ overlayTheme: "a",
+ hidePlaceholderMenuItems: true,
+ closeText: "Close",
+ nativeMenu: true,
+ // This option defaults to true on iOS devices.
+ preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
+ initSelector: "select:not(:jqmData(role='slider'))",
+ mini: false
+ },
+
+ _button: function(){
+ return $( "<div/>" );
+ },
+
+ _setDisabled: function( value ) {
+ this.element.attr( "disabled", value );
+ this.button.attr( "aria-disabled", value );
+ return this._setOption( "disabled", value );
+ },
+
+ _focusButton : function() {
+ var self = this;
+
+ setTimeout( function() {
+ self.button.focus();
+ }, 40);
+ },
+
+ _selectOptions: function() {
+ return this.select.find( "option" );
+ },
+
+ // setup items that are generally necessary for select menu extension
+ _preExtension: function(){
+ var classes = "";
+ // TODO: Post 1.1--once we have time to test thoroughly--any classes manually applied to the original element should be carried over to the enhanced element, with an `-enhanced` suffix. See https://github.com/jquery/jquery-mobile/issues/3577
+ /* if( $el[0].className.length ) {
+ classes = $el[0].className;
+ } */
+ if( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
+ classes = " ui-btn-left";
+ }
+
+ if( !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
+ classes = " ui-btn-right";
+ }
+
+ this.select = this.element.wrap( "<div class='ui-select" + classes + "'>" );
+ this.selectID = this.select.attr( "id" );
+ this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
+ this.isMultiple = this.select[ 0 ].multiple;
+ if ( !this.options.theme ) {
+ this.options.theme = $.mobile.getInheritedTheme( this.select, "c" );
+ }
+ },
+
+ _create: function() {
+ this._preExtension();
+
+ // Allows for extension of the native select for custom selects and other plugins
+ // see select.custom for example extension
+ // TODO explore plugin registration
+ this._trigger( "beforeCreate" );
+
+ this.button = this._button();
+
+ var self = this,
+
+ options = this.options,
+
+ inline = options.inline || this.select.jqmData( "inline" ),
+ mini = options.mini || this.select.jqmData( "mini" ),
+ iconpos = options.icon ? ( options.iconpos || this.select.jqmData( "iconpos" ) ) : false,
+
+ // IE throws an exception at options.item() function when
+ // there is no selected item
+ // select first in this case
+ selectedIndex = this.select[ 0 ].selectedIndex == -1 ? 0 : this.select[ 0 ].selectedIndex,
+
+ // TODO values buttonId and menuId are undefined here
+ button = this.button
+ .text( $( this.select[ 0 ].options.item( selectedIndex ) ).text() )
+ .insertBefore( this.select )
+ .buttonMarkup( {
+ theme: options.theme,
+ icon: options.icon,
+ iconpos: iconpos,
+ inline: inline,
+ corners: options.corners,
+ shadow: options.shadow,
+ iconshadow: options.iconshadow,
+ mini: mini
+ });
+
+ // Opera does not properly support opacity on select elements
+ // In Mini, it hides the element, but not its text
+ // On the desktop,it seems to do the opposite
+ // for these reasons, using the nativeMenu option results in a full native select in Opera
+ if ( options.nativeMenu && window.opera && window.opera.version ) {
+ button.addClass( "ui-select-nativeonly" );
+ }
+
+ // Add counter for multi selects
+ if ( this.isMultiple ) {
+ this.buttonCount = $( "<span>" )
+ .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
+ .hide()
+ .appendTo( button.addClass('ui-li-has-count') );
+ }
+
+ // Disable if specified
+ if ( options.disabled || this.element.attr('disabled')) {
+ this.disable();
+ }
+
+ // Events on native select
+ this.select.change( function() {
+ self.refresh();
+ });
+
+ this.build();
+ },
+
+ build: function() {
+ var self = this;
+
+ this.select
+ .appendTo( self.button )
+ .bind( "vmousedown", function() {
+ // Add active class to button
+ self.button.addClass( $.mobile.activeBtnClass );
+ })
+ .bind( "focus", function() {
+ self.button.addClass( $.mobile.focusClass );
+ })
+ .bind( "blur", function() {
+ self.button.removeClass( $.mobile.focusClass );
+ })
+ .bind( "focus vmouseover", function() {
+ self.button.trigger( "vmouseover" );
+ })
+ .bind( "vmousemove", function() {
+ // Remove active class on scroll/touchmove
+ self.button.removeClass( $.mobile.activeBtnClass );
+ })
+ .bind( "change blur vmouseout", function() {
+ self.button.trigger( "vmouseout" )
+ .removeClass( $.mobile.activeBtnClass );
+ })
+ .bind( "change blur", function() {
+ self.button.removeClass( "ui-btn-down-" + self.options.theme );
+ });
+
+ // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
+ self.button.bind( "vmousedown", function() {
+ if( self.options.preventFocusZoom ){
+ $.mobile.zoom.disable( true );
+ }
+ })
+ .bind( "mouseup", function() {
+ if( self.options.preventFocusZoom ){
+ $.mobile.zoom.enable( true );
+ }
+ });
+ },
+
+ selected: function() {
+ return this._selectOptions().filter( ":selected" );
+ },
+
+ selectedIndices: function() {
+ var self = this;
+
+ return this.selected().map( function() {
+ return self._selectOptions().index( this );
+ }).get();
+ },
+
+ setButtonText: function() {
+ var self = this, selected = this.selected();
+
+ this.button.find( ".ui-btn-text" ).text( function() {
+ if ( !self.isMultiple ) {
+ return selected.text();
+ }
+
+ return selected.length ? selected.map( function() {
+ return $( this ).text();
+ }).get().join( ", " ) : self.placeholder;
+ });
+ },
+
+ setButtonCount: function() {
+ var selected = this.selected();
+
+ // multiple count inside button
+ if ( this.isMultiple ) {
+ this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
+ }
+ },
+
+ refresh: function() {
+ this.setButtonText();
+ this.setButtonCount();
+ },
+
+ // open and close preserved in native selects
+ // to simplify users code when looping over selects
+ open: $.noop,
+ close: $.noop,
+
+ disable: function() {
+ this._setDisabled( true );
+ this.button.addClass( "ui-disabled" );
+ },
+
+ enable: function() {
+ this._setDisabled( false );
+ this.button.removeClass( "ui-disabled" );
+ }
+});
+
+//auto self-init widgets
+$( document ).bind( "pagecreate create", function( e ){
+ $.mobile.selectmenu.prototype.enhanceWithin( e.target, true );
+});
+})( jQuery );
+
+/*
+* custom "selectmenu" plugin
+*/
+
+(function( $, undefined ) {
+ var extendSelect = function( widget ){
+
+ var select = widget.select,
+ selectID = widget.selectID,
+ label = widget.label,
+ thisPage = widget.select.closest( ".ui-page" ),
+ screen = $( "<div>", {"class": "ui-selectmenu-screen ui-screen-hidden"} ).appendTo( thisPage ),
+ selectOptions = widget._selectOptions(),
+ isMultiple = widget.isMultiple = widget.select[ 0 ].multiple,
+ buttonId = selectID + "-button",
+ menuId = selectID + "-menu",
+ menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' data-" +$.mobile.ns + "theme='"+ widget.options.theme +"' data-" +$.mobile.ns + "overlay-theme='"+ widget.options.overlayTheme +"'>" +
+ "<div data-" + $.mobile.ns + "role='header'>" +
+ "<div class='ui-title'>" + label.getEncodedText() + "</div>"+
+ "</div>"+
+ "<div data-" + $.mobile.ns + "role='content'></div>"+
+ "</div>" ),
+
+ listbox = $("<div>", { "class": "ui-selectmenu ui-selectmenu-hidden ui-overlay-shadow ui-corner-all ui-body-" + widget.options.overlayTheme + " " + $.mobile.defaultDialogTransition } ).insertAfter(screen),
+
+ list = $( "<ul>", {
+ "class": "ui-selectmenu-list",
+ "id": menuId,
+ "role": "listbox",
+ "aria-labelledby": buttonId
+ }).attr( "data-" + $.mobile.ns + "theme", widget.options.theme ).appendTo( listbox ),
+
+ header = $( "<div>", {
+ "class": "ui-header ui-bar-" + widget.options.theme
+ }).prependTo( listbox ),
+
+ headerTitle = $( "<h1>", {
+ "class": "ui-title"
+ }).appendTo( header ),
+
+ menuPageContent,
+ menuPageClose,
+ headerClose;
+
+ if( widget.isMultiple ) {
+ headerClose = $( "<a>", {
+ "text": widget.options.closeText,
+ "href": "#",
+ "class": "ui-btn-left"
+ }).attr( "data-" + $.mobile.ns + "iconpos", "notext" ).attr( "data-" + $.mobile.ns + "icon", "delete" ).appendTo( header ).buttonMarkup();
+ }
+
+ $.extend( widget, {
+ select: widget.select,
+ selectID: selectID,
+ buttonId: buttonId,
+ menuId: menuId,
+ thisPage: thisPage,
+ menuPage: menuPage,
+ label: label,
+ screen: screen,
+ selectOptions: selectOptions,
+ isMultiple: isMultiple,
+ theme: widget.options.theme,
+ listbox: listbox,
+ list: list,
+ header: header,
+ headerTitle: headerTitle,
+ headerClose: headerClose,
+ menuPageContent: menuPageContent,
+ menuPageClose: menuPageClose,
+ placeholder: "",
+
+ build: function() {
+ var self = this;
+
+ // Create list from select, update state
+ self.refresh();
+
+ self.select.attr( "tabindex", "-1" ).focus(function() {
+ $( this ).blur();
+ self.button.focus();
+ });
+
+ // Button events
+ self.button.bind( "vclick keydown" , function( event ) {
+ if ( event.type == "vclick" ||
+ event.keyCode && ( event.keyCode === $.mobile.keyCode.ENTER ||
+ event.keyCode === $.mobile.keyCode.SPACE ) ) {
+
+ self.open();
+ event.preventDefault();
+ }
+ });
+
+ // Events for list items
+ self.list.attr( "role", "listbox" )
+ .bind( "focusin", function( e ){
+ $( e.target )
+ .attr( "tabindex", "0" )
+ .trigger( "vmouseover" );
+
+ })
+ .bind( "focusout", function( e ){
+ $( e.target )
+ .attr( "tabindex", "-1" )
+ .trigger( "vmouseout" );
+ })
+ .delegate( "li:not(.ui-disabled, .ui-li-divider)", "click", function( event ) {
+
+ // index of option tag to be selected
+ var oldIndex = self.select[ 0 ].selectedIndex,
+ newIndex = self.list.find( "li:not(.ui-li-divider)" ).index( this ),
+ option = self._selectOptions().eq( newIndex )[ 0 ];
+
+ // toggle selected status on the tag for multi selects
+ option.selected = self.isMultiple ? !option.selected : true;
+
+ // toggle checkbox class for multiple selects
+ if ( self.isMultiple ) {
+ $( this ).find( ".ui-icon" )
+ .toggleClass( "ui-icon-checkbox-on", option.selected )
+ .toggleClass( "ui-icon-checkbox-off", !option.selected );
+ }
+
+ // trigger change if value changed
+ if ( self.isMultiple || oldIndex !== newIndex ) {
+ self.select.trigger( "change" );
+ }
+
+ // hide custom select for single selects only - otherwise focus clicked item
+ // We need to grab the clicked item the hard way, because the list may have been rebuilt
+ if ( self.isMultiple ) {
+ self.list.find( "li:not(.ui-li-divider)" ).eq( newIndex )
+ .addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
+ }
+ else {
+ self.close();
+ }
+
+ event.preventDefault();
+ })
+ .keydown(function( event ) { //keyboard events for menu items
+ var target = $( event.target ),
+ li = target.closest( "li" ),
+ prev, next;
+
+ // switch logic based on which key was pressed
+ switch ( event.keyCode ) {
+ // up or left arrow keys
+ case 38:
+ prev = li.prev().not( ".ui-selectmenu-placeholder" );
+
+ if( prev.is( ".ui-li-divider" ) ) {
+ prev = prev.prev();
+ }
+
+ // if there's a previous option, focus it
+ if ( prev.length ) {
+ target
+ .blur()
+ .attr( "tabindex", "-1" );
+
+ prev.addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
+ }
+
+ return false;
+ break;
+
+ // down or right arrow keys
+ case 40:
+ next = li.next();
+
+ if( next.is( ".ui-li-divider" ) ) {
+ next = next.next();
+ }
+
+ // if there's a next option, focus it
+ if ( next.length ) {
+ target
+ .blur()
+ .attr( "tabindex", "-1" );
+
+ next.addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
+ }
+
+ return false;
+ break;
+
+ // If enter or space is pressed, trigger click
+ case 13:
+ case 32:
+ target.trigger( "click" );
+
+ return false;
+ break;
+ }
+ });
+
+ // button refocus ensures proper height calculation
+ // by removing the inline style and ensuring page inclusion
+ self.menuPage.bind( "pagehide", function() {
+ self.list.appendTo( self.listbox );
+ self._focusButton();
+
+ // TODO centralize page removal binding / handling in the page plugin.
+ // Suggestion from @jblas to do refcounting
+ //
+ // TODO extremely confusing dependency on the open method where the pagehide.remove
+ // bindings are stripped to prevent the parent page from disappearing. The way
+ // we're keeping pages in the DOM right now sucks
+ //
+ // rebind the page remove that was unbound in the open function
+ // to allow for the parent page removal from actions other than the use
+ // of a dialog sized custom select
+ //
+ // doing this here provides for the back button on the custom select dialog
+ $.mobile._bindPageRemove.call( self.thisPage );
+ });
+
+ // Events on "screen" overlay
+ self.screen.bind( "vclick", function( event ) {
+ self.close();
+ });
+
+ // Close button on small overlays
+ if( self.isMultiple ){
+ self.headerClose.click( function() {
+ if ( self.menuType == "overlay" ) {
+ self.close();
+ return false;
+ }
+ });
+ }
+
+ // track this dependency so that when the parent page
+ // is removed on pagehide it will also remove the menupage
+ self.thisPage.addDependents( this.menuPage );
+ },
+
+ _isRebuildRequired: function() {
+ var list = this.list.find( "li" ),
+ options = this._selectOptions();
+
+ // TODO exceedingly naive method to determine difference
+ // ignores value changes etc in favor of a forcedRebuild
+ // from the user in the refresh method
+ return options.text() !== list.text();
+ },
+
+ selected: function() {
+ return this._selectOptions().filter( ":selected:not(:jqmData(placeholder='true'))" );
+ },
+
+ refresh: function( forceRebuild , foo ){
+ var self = this,
+ select = this.element,
+ isMultiple = this.isMultiple,
+ indicies;
+
+ if ( forceRebuild || this._isRebuildRequired() ) {
+ self._buildList();
+ }
+
+ indicies = this.selectedIndices();
+
+ self.setButtonText();
+ self.setButtonCount();
+
+ self.list.find( "li:not(.ui-li-divider)" )
+ .removeClass( $.mobile.activeBtnClass )
+ .attr( "aria-selected", false )
+ .each(function( i ) {
+
+ if ( $.inArray( i, indicies ) > -1 ) {
+ var item = $( this );
+
+ // Aria selected attr
+ item.attr( "aria-selected", true );
+
+ // Multiple selects: add the "on" checkbox state to the icon
+ if ( self.isMultiple ) {
+ item.find( ".ui-icon" ).removeClass( "ui-icon-checkbox-off" ).addClass( "ui-icon-checkbox-on" );
+ } else {
+ if( item.is( ".ui-selectmenu-placeholder" ) ) {
+ item.next().addClass( $.mobile.activeBtnClass );
+ } else {
+ item.addClass( $.mobile.activeBtnClass );
+ }
+ }
+ }
+ });
+ },
+
+ close: function() {
+ if ( this.options.disabled || !this.isOpen ) {
+ return;
+ }
+
+ var self = this;
+
+ if ( self.menuType == "page" ) {
+ // doesn't solve the possible issue with calling change page
+ // where the objects don't define data urls which prevents dialog key
+ // stripping - changePage has incoming refactor
+ window.history.back();
+ } else {
+ self.screen.addClass( "ui-screen-hidden" );
+ self.listbox.addClass( "ui-selectmenu-hidden" ).removeAttr( "style" ).removeClass( "in" );
+ self.list.appendTo( self.listbox );
+ self._focusButton();
+ }
+
+ // allow the dialog to be closed again
+ self.isOpen = false;
+ },
+
+ open: function() {
+ if ( this.options.disabled ) {
+ return;
+ }
+
+ var self = this,
+ $window = $( window ),
+ selfListParent = self.list.parent(),
+ menuHeight = selfListParent.outerHeight(),
+ menuWidth = selfListParent.outerWidth(),
+ activePage = $( ".ui-page-active" ),
+ tScrollElem = activePage,
+ scrollTop = $window.scrollTop(),
+ btnOffset = self.button.offset().top,
+ screenHeight = $window.height(),
+ screenWidth = $window.width();
+
+ //add active class to button
+ self.button.addClass( $.mobile.activeBtnClass );
+
+ //remove after delay
+ setTimeout( function() {
+ self.button.removeClass( $.mobile.activeBtnClass );
+ }, 300);
+
+ function focusMenuItem() {
+ var selector = self.list.find( "." + $.mobile.activeBtnClass + " a" );
+ if ( selector.length === 0 ) {
+ selector = self.list.find( "li.ui-btn:not(:jqmData(placeholder='true')) a" );
+ }
+ selector.first().focus().closest( "li" ).addClass( "ui-btn-down-" + widget.options.theme );
+ }
+
+ if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
+
+ self.menuPage.appendTo( $.mobile.pageContainer ).page();
+ self.menuPageContent = menuPage.find( ".ui-content" );
+ self.menuPageClose = menuPage.find( ".ui-header a" );
+
+ // prevent the parent page from being removed from the DOM,
+ // otherwise the results of selecting a list item in the dialog
+ // fall into a black hole
+ self.thisPage.unbind( "pagehide.remove" );
+
+ //for WebOS/Opera Mini (set lastscroll using button offset)
+ if ( scrollTop == 0 && btnOffset > screenHeight ) {
+ self.thisPage.one( "pagehide", function() {
+ $( this ).jqmData( "lastScroll", btnOffset );
+ });
+ }
+
+ self.menuPage.one( "pageshow", function() {
+ focusMenuItem();
+ self.isOpen = true;
+ });
+
+ self.menuType = "page";
+ self.menuPageContent.append( self.list );
+ self.menuPage.find("div .ui-title").text(self.label.text());
+ $.mobile.changePage( self.menuPage, {
+ transition: $.mobile.defaultDialogTransition
+ });
+ } else {
+ self.menuType = "overlay";
+
+ self.screen.height( $(document).height() )
+ .removeClass( "ui-screen-hidden" );
+
+ // Try and center the overlay over the button
+ var roomtop = btnOffset - scrollTop,
+ roombot = scrollTop + screenHeight - btnOffset,
+ halfheight = menuHeight / 2,
+ maxwidth = parseFloat( self.list.parent().css( "max-width" ) ),
+ newtop, newleft;
+
+ if ( roomtop > menuHeight / 2 && roombot > menuHeight / 2 ) {
+ newtop = btnOffset + ( self.button.outerHeight() / 2 ) - halfheight;
+ } else {
+ // 30px tolerance off the edges
+ newtop = roomtop > roombot ? scrollTop + screenHeight - menuHeight - 30 : scrollTop + 30;
+ }
+
+ // If the menuwidth is smaller than the screen center is
+ if ( menuWidth < maxwidth ) {
+ newleft = ( screenWidth - menuWidth ) / 2;
+ } else {
+
+ //otherwise insure a >= 30px offset from the left
+ newleft = self.button.offset().left + self.button.outerWidth() / 2 - menuWidth / 2;
+
+ // 30px tolerance off the edges
+ if ( newleft < 30 ) {
+ newleft = 30;
+ } else if ( (newleft + menuWidth) > screenWidth ) {
+ newleft = screenWidth - menuWidth - 30;
+ }
+ }
+
+ self.listbox.append( self.list )
+ .removeClass( "ui-selectmenu-hidden" )
+ .css({
+ top: newtop,
+ left: newleft
+ })
+ .addClass( "in" );
+
+ focusMenuItem();
+
+ // duplicate with value set in page show for dialog sized selects
+ self.isOpen = true;
+ }
+ },
+
+ _buildList: function() {
+ var self = this,
+ o = this.options,
+ placeholder = this.placeholder,
+ needPlaceholder = true,
+ optgroups = [],
+ lis = [],
+ dataIcon = self.isMultiple ? "checkbox-off" : "false";
+
+ self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
+
+ var $options = self.select.find("option"),
+ numOptions = $options.length,
+ select = this.select[ 0 ],
+ dataPrefix = 'data-' + $.mobile.ns,
+ dataIndexAttr = dataPrefix + 'option-index',
+ dataIconAttr = dataPrefix + 'icon',
+ dataRoleAttr = dataPrefix + 'role',
+ dataPlaceholderAttr = dataPrefix + 'placeholder',
+ fragment = document.createDocumentFragment(),
+ isPlaceholderItem = false,
+ optGroup;
+
+ for (var i = 0; i < numOptions;i++, isPlaceholderItem = false){
+ var option = $options[i],
+ $option = $(option),
+ parent = option.parentNode,
+ text = $option.text(),
+ anchor = document.createElement('a'),
+ classes = [];
+
+ anchor.setAttribute('href','#');
+ anchor.appendChild(document.createTextNode(text));
+
+ // Are we inside an optgroup?
+ if (parent !== select && parent.nodeName.toLowerCase() === "optgroup"){
+ var optLabel = parent.getAttribute('label');
+ if ( optLabel != optGroup) {
+ var divider = document.createElement('li');
+ divider.setAttribute(dataRoleAttr,'list-divider');
+ divider.setAttribute('role','option');
+ divider.setAttribute('tabindex','-1');
+ divider.appendChild(document.createTextNode(optLabel));
+ fragment.appendChild(divider);
+ optGroup = optLabel;
+ }
+ }
+
+ if (needPlaceholder && (!option.getAttribute( "value" ) || text.length == 0 || $option.jqmData( "placeholder" ))) {
+ needPlaceholder = false;
+ isPlaceholderItem = true;
+
+ // If we have identified a placeholder, mark it retroactively in the select as well
+ option.setAttribute( dataPlaceholderAttr, true );
+ if ( o.hidePlaceholderMenuItems ) {
+ classes.push( "ui-selectmenu-placeholder" );
+ }
+ if (!placeholder) {
+ placeholder = self.placeholder = text;
+ }
+ }
+
+ var item = document.createElement('li');
+ if ( option.disabled ) {
+ classes.push( "ui-disabled" );
+ item.setAttribute('aria-disabled',true);
+ }
+ item.setAttribute(dataIndexAttr,i);
+ item.setAttribute(dataIconAttr,dataIcon);
+ if ( isPlaceholderItem ) {
+ item.setAttribute( dataPlaceholderAttr, true );
+ }
+ item.className = classes.join(" ");
+ item.setAttribute('role','option');
+ anchor.setAttribute('tabindex','-1');
+ item.appendChild(anchor);
+ fragment.appendChild(item);
+ }
+
+ self.list[0].appendChild(fragment);
+
+ // Hide header if it's not a multiselect and there's no placeholder
+ if ( !this.isMultiple && !placeholder.length ) {
+ this.header.hide();
+ } else {
+ this.headerTitle.text( this.placeholder );
+ }
+
+ // Now populated, create listview
+ self.list.listview();
+ },
+
+ _button: function(){
+ return $( "<a>", {
+ "href": "#",
+ "role": "button",
+ // TODO value is undefined at creation
+ "id": this.buttonId,
+ "aria-haspopup": "true",
+
+ // TODO value is undefined at creation
+ "aria-owns": this.menuId
+ });
+ }
+ });
+ };
+
+ // issue #3894 - core doesn't triggered events on disabled delegates
+ $( document ).bind( "selectmenubeforecreate", function( event ){
+ var selectmenuWidget = $( event.target ).data( "selectmenu" );
+
+ if( !selectmenuWidget.options.nativeMenu ){
+ extendSelect( selectmenuWidget );
+ }
+ });
+})( jQuery );
+
+(function( $, undefined ) {
+
+
+ $.widget( "mobile.fixedtoolbar", $.mobile.widget, {
+ options: {
+ visibleOnPageShow: true,
+ disablePageZoom: true,
+ transition: "slide", //can be none, fade, slide (slide maps to slideup or slidedown)
+ fullscreen: false,
+ tapToggle: true,
+ tapToggleBlacklist: "a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed",
+ hideDuringFocus: "input, textarea, select",
+ updatePagePadding: true,
+ trackPersistentToolbars: true,
+
+ // Browser detection! Weeee, here we go...
+ // Unfortunately, position:fixed is costly, not to mention probably impossible, to feature-detect accurately.
+ // Some tests exist, but they currently return false results in critical devices and browsers, which could lead to a broken experience.
+ // Testing fixed positioning is also pretty obtrusive to page load, requiring injected elements and scrolling the window
+ // The following function serves to rule out some popular browsers with known fixed-positioning issues
+ // This is a plugin option like any other, so feel free to improve or overwrite it
+ supportBlacklist: function(){
+ var w = window,
+ ua = navigator.userAgent,
+ platform = navigator.platform,
+ // Rendering engine is Webkit, and capture major version
+ wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
+ wkversion = !!wkmatch && wkmatch[ 1 ],
+ ffmatch = ua.match( /Fennec\/([0-9]+)/ ),
+ ffversion = !!ffmatch && ffmatch[ 1 ],
+ operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ),
+ omversion = !!operammobilematch && operammobilematch[ 1 ];
+
+ if(
+ // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
+ ( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 )
+ ||
+ // Opera Mini
+ ( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" )
+ ||
+ ( operammobilematch && omversion < 7458 )
+ ||
+ //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
+ ( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 )
+ ||
+ // Firefox Mobile before 6.0 -
+ ( ffversion && ffversion < 6 )
+ ||
+ // WebOS less than 3
+ ( "palmGetResource" in window && wkversion && wkversion < 534 )
+ ||
+ // MeeGo
+ ( ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1 )
+ ){
+ return true;
+ }
+
+ return false;
+ },
+ initSelector: ":jqmData(position='fixed')"
+ },
+
+ _create: function() {
+
+ var self = this,
+ o = self.options,
+ $el = self.element,
+ tbtype = $el.is( ":jqmData(role='header')" ) ? "header" : "footer",
+ $page = $el.closest(".ui-page");
+
+ // Feature detecting support for
+ if( o.supportBlacklist() ){
+ self.destroy();
+ return;
+ }
+
+ $el.addClass( "ui-"+ tbtype +"-fixed" );
+
+ // "fullscreen" overlay positioning
+ if( o.fullscreen ){
+ $el.addClass( "ui-"+ tbtype +"-fullscreen" );
+ $page.addClass( "ui-page-" + tbtype + "-fullscreen" );
+ }
+ // If not fullscreen, add class to page to set top or bottom padding
+ else{
+ $page.addClass( "ui-page-" + tbtype + "-fixed" );
+ }
+
+ self._addTransitionClass();
+ self._bindPageEvents();
+ self._bindToggleHandlers();
+ },
+
+ _addTransitionClass: function(){
+ var tclass = this.options.transition;
+
+ if( tclass && tclass !== "none" ){
+ // use appropriate slide for header or footer
+ if( tclass === "slide" ){
+ tclass = this.element.is( ".ui-header" ) ? "slidedown" : "slideup";
+ }
+
+ this.element.addClass( tclass );
+ }
+ },
+
+ _bindPageEvents: function(){
+ var self = this,
+ o = self.options,
+ $el = self.element;
+
+ //page event bindings
+ // Fixed toolbars require page zoom to be disabled, otherwise usability issues crop up
+ // This method is meant to disable zoom while a fixed-positioned toolbar page is visible
+ $el.closest( ".ui-page" )
+ .bind( "pagebeforeshow", function(){
+ if( o.disablePageZoom ){
+ $.mobile.zoom.disable( true );
+ }
+ if( !o.visibleOnPageShow ){
+ self.hide( true );
+ }
+ } )
+ .bind( "webkitAnimationStart animationstart updatelayout", function(){
+ var thisPage = this;
+ if( o.updatePagePadding ){
+ self.updatePagePadding( thisPage );
+ }
+ })
+ .bind( "pageshow", function(){
+ var thisPage = this;
+ self.updatePagePadding( thisPage );
+ if( o.updatePagePadding ){
+ $( window ).bind( "throttledresize." + self.widgetName, function(){
+ self.updatePagePadding( thisPage );
+ });
+ }
+ })
+ .bind( "pagebeforehide", function( e, ui ){
+ if( o.disablePageZoom ){
+ $.mobile.zoom.enable( true );
+ }
+ if( o.updatePagePadding ){
+ $( window ).unbind( "throttledresize." + self.widgetName );
+ }
+
+ if( o.trackPersistentToolbars ){
+ var thisFooter = $( ".ui-footer-fixed:jqmData(id)", this ),
+ thisHeader = $( ".ui-header-fixed:jqmData(id)", this ),
+ nextFooter = thisFooter.length && ui.nextPage && $( ".ui-footer-fixed:jqmData(id='" + thisFooter.jqmData( "id" ) + "')", ui.nextPage ),
+ nextHeader = thisHeader.length && ui.nextPage && $( ".ui-header-fixed:jqmData(id='" + thisHeader.jqmData( "id" ) + "')", ui.nextPage );
+
+ nextFooter = nextFooter || $();
+
+ if( nextFooter.length || nextHeader.length ){
+
+ nextFooter.add( nextHeader ).appendTo( $.mobile.pageContainer );
+
+ ui.nextPage.one( "pageshow", function(){
+ nextFooter.add( nextHeader ).appendTo( this );
+ });
+ }
+ }
+ });
+ },
+
+ _visible: true,
+
+ // This will set the content element's top or bottom padding equal to the toolbar's height
+ updatePagePadding: function( tbPage ) {
+ var $el = this.element,
+ header = $el.is( ".ui-header" );
+
+ // This behavior only applies to "fixed", not "fullscreen"
+ if( this.options.fullscreen ){ return; }
+
+ tbPage = tbPage || $el.closest( ".ui-page" );
+ $( tbPage ).css( "padding-" + ( header ? "top" : "bottom" ), $el.outerHeight() );
+ },
+
+ _useTransition: function( notransition ){
+ var $win = $( window ),
+ $el = this.element,
+ scroll = $win.scrollTop(),
+ elHeight = $el.height(),
+ pHeight = $el.closest( ".ui-page" ).height(),
+ viewportHeight = $.mobile.getScreenHeight(),
+ tbtype = $el.is( ":jqmData(role='header')" ) ? "header" : "footer";
+
+ return !notransition &&
+ ( this.options.transition && this.options.transition !== "none" &&
+ (
+ ( tbtype === "header" && !this.options.fullscreen && scroll > elHeight ) ||
+ ( tbtype === "footer" && !this.options.fullscreen && scroll + viewportHeight < pHeight - elHeight )
+ ) || this.options.fullscreen
+ );
+ },
+
+ show: function( notransition ){
+ var hideClass = "ui-fixed-hidden",
+ $el = this.element;
+
+ if( this._useTransition( notransition ) ){
+ $el
+ .removeClass( "out " + hideClass )
+ .addClass( "in" );
+ }
+ else {
+ $el.removeClass( hideClass );
+ }
+ this._visible = true;
+ },
+
+ hide: function( notransition ){
+ var hideClass = "ui-fixed-hidden",
+ $el = this.element,
+ // if it's a slide transition, our new transitions need the reverse class as well to slide outward
+ outclass = "out" + ( this.options.transition === "slide" ? " reverse" : "" );
+
+ if( this._useTransition( notransition ) ){
+ $el
+ .addClass( outclass )
+ .removeClass( "in" )
+ .animationComplete( function(){
+ $el.addClass( hideClass ).removeClass( outclass );
+ });
+ }
+ else {
+ $el.addClass( hideClass ).removeClass( outclass );
+ }
+ this._visible = false;
+ },
+
+ toggle: function(){
+ this[ this._visible ? "hide" : "show" ]();
+ },
+
+ _bindToggleHandlers: function(){
+ var self = this,
+ o = self.options,
+ $el = self.element;
+
+ // tap toggle
+ $el.closest( ".ui-page" )
+ .bind( "vclick", function( e ){
+ if( o.tapToggle && !$( e.target ).closest( o.tapToggleBlacklist ).length ){
+ self.toggle();
+ }
+ })
+ .bind( "focusin focusout", function( e ){
+ if( screen.width < 500 && $( e.target ).is( o.hideDuringFocus ) && !$( e.target ).closest( ".ui-header-fixed, .ui-footer-fixed" ).length ){
+ self[ ( e.type === "focusin" && self._visible ) ? "hide" : "show" ]();
+ }
+ });
+ },
+
+ destroy: function(){
+ this.element.removeClass( "ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden" );
+ this.element.closest( ".ui-page" ).removeClass( "ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen" );
+ }
+
+ });
+
+ //auto self-init widgets
+ $( document )
+ .bind( "pagecreate create", function( e ){
+
+ // DEPRECATED in 1.1: support for data-fullscreen=true|false on the page element.
+ // This line ensures it still works, but we recommend moving the attribute to the toolbars themselves.
+ if( $( e.target ).jqmData( "fullscreen" ) ){
+ $( $.mobile.fixedtoolbar.prototype.options.initSelector, e.target ).not( ":jqmData(fullscreen)" ).jqmData( "fullscreen", true );
+ }
+
+ $.mobile.fixedtoolbar.prototype.enhanceWithin( e.target );
+ });
+
+})( jQuery );
+
+( function( $, window ) {
+
+ // This fix addresses an iOS bug, so return early if the UA claims it's something else.
+ if( !(/iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1 ) ){
+ return;
+ }
+
+ var zoom = $.mobile.zoom,
+ evt, x, y, z, aig;
+
+ function checkTilt( e ){
+ evt = e.originalEvent;
+ aig = evt.accelerationIncludingGravity;
+
+ x = Math.abs( aig.x );
+ y = Math.abs( aig.y );
+ z = Math.abs( aig.z );
+
+ // If portrait orientation and in one of the danger zones
+ if( !window.orientation && ( x > 7 || ( ( z > 6 && y < 8 || z < 8 && y > 6 ) && x > 5 ) ) ){
+ if( zoom.enabled ){
+ zoom.disable();
+ }
+ }
+ else if( !zoom.enabled ){
+ zoom.enable();
+ }
+ }
+
+ $( window )
+ .bind( "orientationchange.iosorientationfix", zoom.enable )
+ .bind( "devicemotion.iosorientationfix", checkTilt );
+
+}( jQuery, this ));
+
+( function( $, window, undefined ) {
+ var $html = $( "html" ),
+ $head = $( "head" ),
+ $window = $( window );
+
+ // trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
+ $( window.document ).trigger( "mobileinit" );
+
+ // support conditions
+ // if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
+ // otherwise, proceed with the enhancements
+ if ( !$.mobile.gradeA() ) {
+ return;
+ }
+
+ // override ajaxEnabled on platforms that have known conflicts with hash history updates
+ // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
+ if ( $.mobile.ajaxBlacklist ) {
+ $.mobile.ajaxEnabled = false;
+ }
+
+ // Add mobile, initial load "rendering" classes to docEl
+ $html.addClass( "ui-mobile ui-mobile-rendering" );
+
+ // This is a fallback. If anything goes wrong (JS errors, etc), or events don't fire,
+ // this ensures the rendering class is removed after 5 seconds, so content is visible and accessible
+ setTimeout( hideRenderingClass, 5000 );
+
+ // loading div which appears during Ajax requests
+ // will not appear if $.mobile.loadingMessage is false
+ var loaderClass = "ui-loader",
+ $loader = $( "<div class='" + loaderClass + "'><span class='ui-icon ui-icon-loading'></span><h1></h1></div>" );
+
+ // For non-fixed supportin browsers. Position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
+ function fakeFixLoader(){
+ var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
+
+ $loader
+ .css({
+ top: $.support.scrollTop && $window.scrollTop() + $window.height() / 2 ||
+ activeBtn.length && activeBtn.offset().top || 100
+ });
+ }
+
+ // check position of loader to see if it appears to be "fixed" to center
+ // if not, use abs positioning
+ function checkLoaderPosition(){
+ var offset = $loader.offset(),
+ scrollTop = $window.scrollTop(),
+ screenHeight = $.mobile.getScreenHeight();
+
+ if( offset.top < scrollTop || (offset.top - scrollTop) > screenHeight ) {
+ $loader.addClass( "ui-loader-fakefix" );
+ fakeFixLoader();
+ $window
+ .unbind( "scroll", checkLoaderPosition )
+ .bind( "scroll", fakeFixLoader );
+ }
+ }
+
+ //remove initial build class (only present on first pageshow)
+ function hideRenderingClass(){
+ $html.removeClass( "ui-mobile-rendering" );
+ }
+
+ $.extend($.mobile, {
+ // turn on/off page loading message.
+ showPageLoadingMsg: function( theme, msgText, textonly ) {
+ $html.addClass( "ui-loading" );
+
+ if ( $.mobile.loadingMessage ) {
+ // text visibility from argument takes priority
+ var textVisible = textonly || $.mobile.loadingMessageTextVisible;
+
+ theme = theme || $.mobile.loadingMessageTheme,
+
+ $loader
+ .attr( "class", loaderClass + " ui-corner-all ui-body-" + ( theme || "a" ) + " ui-loader-" + ( textVisible ? "verbose" : "default" ) + ( textonly ? " ui-loader-textonly" : "" ) )
+ .find( "h1" )
+ .text( msgText || $.mobile.loadingMessage )
+ .end()
+ .appendTo( $.mobile.pageContainer );
+
+ checkLoaderPosition();
+ $window.bind( "scroll", checkLoaderPosition );
+ }
+ },
+
+ hidePageLoadingMsg: function() {
+ $html.removeClass( "ui-loading" );
+
+ if( $.mobile.loadingMessage ){
+ $loader.removeClass( "ui-loader-fakefix" );
+ }
+
+ $( window ).unbind( "scroll", fakeFixLoader );
+ $( window ).unbind( "scroll", checkLoaderPosition );
+ },
+
+ // find and enhance the pages in the dom and transition to the first page.
+ initializePage: function() {
+ // find present pages
+ var $pages = $( ":jqmData(role='page'), :jqmData(role='dialog')" );
+
+ // if no pages are found, create one with body's inner html
+ if ( !$pages.length ) {
+ $pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
+ }
+
+ // add dialogs, set data-url attrs
+ $pages.each(function() {
+ var $this = $(this);
+
+ // unless the data url is already set set it to the pathname
+ if ( !$this.jqmData("url") ) {
+ $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) || location.pathname + location.search );
+ }
+ });
+
+ // define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
+ $.mobile.firstPage = $pages.first();
+
+ // define page container
+ $.mobile.pageContainer = $pages.first().parent().addClass( "ui-mobile-viewport" );
+
+ // alert listeners that the pagecontainer has been determined for binding
+ // to events triggered on it
+ $window.trigger( "pagecontainercreate" );
+
+ // cue page loading message
+ $.mobile.showPageLoadingMsg();
+
+ //remove initial build class (only present on first pageshow)
+ hideRenderingClass();
+
+ // if hashchange listening is disabled, there's no hash deeplink,
+ // the hash is not valid (contains more than one # or does not start with #)
+ // or there is no page with that hash, change to the first page in the DOM
+ // Remember, however, that the hash can also be a path!
+ if ( ! ( $.mobile.hashListeningEnabled &&
+ $.mobile.path.isHashValid( location.hash ) &&
+ ( $( location.hash + ':jqmData(role="page")' ).length ||
+ $.mobile.path.isPath( location.hash ) ) ) ) {
+ $.mobile.changePage( $.mobile.firstPage, { transition: "none", reverse: true, changeHash: false, fromHashChange: true } );
+ }
+ // otherwise, trigger a hashchange to load a deeplink
+ else {
+ $window.trigger( "hashchange", [ true ] );
+ }
+ }
+ });
+
+ // initialize events now, after mobileinit has occurred
+ $.mobile.navreadyDeferred.resolve();
+
+ // check which scrollTop value should be used by scrolling to 1 immediately at domready
+ // then check what the scroll top is. Android will report 0... others 1
+ // note that this initial scroll won't hide the address bar. It's just for the check.
+ $(function() {
+ window.scrollTo( 0, 1 );
+
+ // if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
+ // it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
+ // so if it's 1, use 0 from now on
+ $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $(window).scrollTop() === 1 ) ? 0 : 1;
+
+
+ // TODO: Implement a proper registration mechanism with dependency handling in order to not have exceptions like the one below
+ //auto self-init widgets for those widgets that have a soft dependency on others
+ if ( $.fn.controlgroup ) {
+ $( document ).bind( "pagecreate create", function( e ){
+ $( ":jqmData(role='controlgroup')", e.target )
+ .jqmEnhanceable()
+ .controlgroup({ excludeInvisible: false });
+ });
+ }
+
+ //dom-ready inits
+ if( $.mobile.autoInitializePage ){
+ $.mobile.initializePage();
+ }
+
+ // window load event
+ // hide iOS browser chrome on load
+ $window.load( $.mobile.silentScroll );
+
+ if ( !$.support.cssPointerEvents ) {
+ // IE and Opera don't support CSS pointer-events: none that we use to disable link-based buttons
+ // by adding the 'ui-disabled' class to them. Using a JavaScript workaround for those browser.
+ // https://github.com/jquery/jquery-mobile/issues/3558
+
+ $( document ).delegate( ".ui-disabled", "vclick",
+ function( e ) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+ );
+ }
+ });
+}( jQuery, this ));
+
+
+}));
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>aps-environment</key>
+ <string>development</string>
+ </dict>
+</plist>
--- /dev/null
+/*
+ * Author: Derek Chia <snipking@gmail.com>
+ * common functions for cordova plugin after hook
+ */
+const fs = require('fs');
+const path = require('path');
+
+module.exports.addAPNSinEntitlements = (entitlementPath, isProduction) => {
+ if( fs.existsSync(entitlementPath) ) {
+ fs.readFile(entitlementPath, "utf8", function(err, data) {
+ if (err) {
+ throw err;
+ }
+
+ console.log("Reading entitlements file asynchronously");
+
+ let toInsert = '<key>aps-environment</key>\n' +
+ '\t\t<string>development</string>';
+ if(isProduction) {
+ toInsert = '<key>aps-environment</key>\n' +
+ '\t\t<string>production</string>';
+ }
+
+ let re1 = new RegExp('<key>aps-environment<\/key>(.|[\r\n])*<string>.*<\/string>');
+ let matched = data.match(re1);
+ let result;
+ if (matched === null) {
+ if(data.match(/<\/dict>/g)) {
+ result = data.replace(/<\/dict>/, '\t' + toInsert + '\n\t</dict>');
+ } else if(data.match(/<dict\/>/g)) {
+ result = data.replace(/<dict\/>/, '\t<dict>\n\t\t' + toInsert + '\n\t</dict>');
+ }
+ } else {
+ result = data.replace(re1, toInsert);
+ }
+
+ // write result to entitlements file
+ fs.writeFile(entitlementPath, result, {"encoding": 'utf8'}, function(err) {
+ if (err) {
+ throw err;
+ }
+ console.log(entitlementPath + " written successfully");
+ });
+ });
+ } else {
+ console.log("Entitlement File '" + entitlementPath + "' not found. Make sure your ios platform upper than 4.3.0");
+ }
+}
+
+module.exports.removeAPNSinEntitlements = (entitlementPath) => {
+ if( fs.existsSync(entitlementPath) ) {
+ fs.readFile(entitlementPath, "utf8", function(err, data) {
+ if (err) {
+ throw err;
+ }
+
+ console.log("Reading entitlements file asynchronously");
+
+ let re1 = new RegExp('<key>aps-environment<\/key>(.|[\r\n])*<string>.*<\/string>');
+ let matched = data.match(re1);
+ let result;
+ if (matched != null) {
+ result = data.replace(re1, "");
+ }
+
+ // write result to entitlements file
+ fs.writeFile(entitlementPath, result, {"encoding": 'utf8'}, function(err) {
+ if (err) {
+ throw err;
+ }
+ console.log(entitlementPath + " written successfully");
+ });
+ });
+ } else {
+ console.log("Entitlement File '" + entitlementPath + "' not found. Make sure your ios platform upper than 4.3.0");
+ }
+}
+
+module.exports.getXcodeProjName = (searchPath) => {
+ if(searchPath == null || searchPath == undefined) {
+ searchPath = './';
+ }
+ let resultFolderName = null;
+ let folderNames = fs.readdirSync(searchPath).filter(file => fs.lstatSync(path.join(searchPath, file)).isDirectory());
+ let folderNamesReg = new RegExp('.*\.xcodeproj', 'g') // get filder name like `*.xcodeproj`
+ for(let folderName of folderNames) {
+ if(folderName.match(folderNamesReg)) {
+ resultFolderName = folderName;
+ break;
+ }
+ }
+ return resultFolderName.substr(0, resultFolderName.length - 10);
+}
--- /dev/null
+/*
+ * Author: Derek Chia <snipking@gmail.com>
+ * Cordova plugin after hook to disable `Push Notification` capability for XCode 8
+ */
+
+const fs = require('fs');
+const path = require('path');
+let commonFuncs = require('./common');
+
+/**
+ * remove APNS env from cordova project Entitlements-Debug.plist and Entitlements-Release.plist
+ * This two file will work when xcode archive app
+ */
+let disablePushNotificationForCI = (basePath, xcodeprojName) => {
+ commonFuncs.removeAPNSinEntitlements(basePath + xcodeprojName + '/Entitlements-Debug.plist');
+ commonFuncs.removeAPNSinEntitlements(basePath + xcodeprojName + '/Entitlements-Release.plist');
+}
+
+/**
+ * remove APNS env to entitlement file; disable Push Notification capability in .pbxproj file
+ * This two file will work when xcode archive app
+ */
+let disablePushNotificationForXCode = (entitlementsPath, pbxprojPath) => {
+ /**
+ * remove APNS env to entitlement file
+ */
+ if( fs.existsSync(entitlementsPath) ) {
+ commonFuncs.removeAPNSinEntitlements(entitlementsPath);
+ }
+
+ /**
+ * disable Push Notification capability in .pbxproj file
+ * equally disable "Push Notification" switch in xcode
+ */
+ fs.readFile(pbxprojPath, "utf8", function(err, data) {
+ if (err) {
+ throw err;
+ }
+ console.log("Reading pbxproj file asynchronously");
+
+ // turn off Push Notification Capability
+ let re4rep = new RegExp('isa = PBXProject;(.|[\r\n])*TargetAttributes(.|[\r\n])*SystemCapabilities(.|[\r\n])*com\.apple\.Push = {(.|[\r\n])*enabled = [01]');
+ let parts = re4rep.exec(data);
+ if(parts !== null && parts !== undefined && parts.length > 0) {
+ result = data.replace(re4rep, parts[0].substr(0, parts[0].length - 1) + '0');
+
+ // write result to project.pbxproj
+ fs.writeFile(pbxprojPath, result, {"encoding": 'utf8'}, function(err) {
+ if (err) {
+ throw err;
+ }
+ console.log(pbxprojPath + " written successfully");
+ });
+ }
+ });
+}
+
+let basePath = './platforms/ios/';
+let buildType = 'dev';
+let xcodeprojName = commonFuncs.getXcodeProjName(basePath);
+let pbxprojPath = basePath + xcodeprojName + '.xcodeproj/project.pbxproj';
+let entitlementsPath = basePath + xcodeprojName + '/' + xcodeprojName + '.entitlements';
+
+disablePushNotificationForCI(basePath, xcodeprojName);
+
+disablePushNotificationForXCode(entitlementsPath, pbxprojPath);
--- /dev/null
+/*
+ * Author: Derek Chia <snipking@gmail.com>
+ * Cordova plugin after hook to enable `Push Notification` capability for XCode 8
+ */
+
+const fs = require('fs');
+const path = require('path');
+let commonFuncs = require('./common');
+
+/**
+ * add APNS env to cordova project Entitlements-Debug.plist and Entitlements-Release.plist
+ * This two file will work when xcode archive app
+ */
+let enablePushNotificationForCI = (basePath, xcodeprojName) => {
+ commonFuncs.addAPNSinEntitlements(basePath + xcodeprojName + '/Entitlements-Debug.plist', false);
+ commonFuncs.addAPNSinEntitlements(basePath + xcodeprojName + '/Entitlements-Release.plist', true);
+}
+
+/**
+ * add APNS env to entitlement file; enable Push Notification capability in .pbxproj file
+ * This two file will work when xcode archive app
+ */
+let enablePushNotificationForXCode = (entitlementsPath, pbxprojPath, cordovaBuildConfig) => {
+ console.log('will enable push notification capability for XCode');
+ let needAddEntitlementToPbxproj = false;
+ /**
+ * add APNS env to entitlement file
+ * without this file will cause a worning in xcode
+ */
+ if( fs.existsSync(entitlementsPath) ) {
+ commonFuncs.addAPNSinEntitlements(entitlementsPath, false);
+ } else {
+ // copy default entitlements file
+ fs.readFile(__dirname + '/apns.entitlements', 'utf8', function(err, data) {
+ if (err) {
+ throw err;
+ }
+
+ fs.writeFileSync(entitlementsPath, data);
+ console.log(entitlementsPath + " written successfully");
+ });
+
+ needAddEntitlementToPbxproj = true;
+ }
+
+ /**
+ * enable Push Notification capability in .pbxproj file
+ * equally enable "Push Notification" switch in xcode
+ */
+ fs.readFile(pbxprojPath, "utf8", function(err, data) {
+ if (err) {
+ throw err;
+ }
+ console.log("Reading pbxproj file asynchronously");
+
+ // add Push Notification Capability
+ let re1 = new RegExp('isa = PBXProject;(.|[\r\n])*TargetAttributes', 'g');
+ let re1rep = new RegExp('isa = PBXProject;(.|[\r\n])*attributes = {', 'g');
+ let re2 = new RegExp('(?:isa = PBXProject;(.|[\r\n])*TargetAttributes(.|[\r\n])*)SystemCapabilities', 'g');
+ let re2rep = new RegExp('isa = PBXProject;(.|[\r\n])*TargetAttributes = {', 'g');
+ let re3 = new RegExp('(?:isa = PBXProject;(.|[\r\n])*TargetAttributes(.|[\r\n])*SystemCapabilities(.|[\r\n])*)com\.apple\.Push', 'g');
+ let re3rep = new RegExp('isa = PBXProject;(.|[\r\n])*TargetAttributes(.|[\r\n])*SystemCapabilities = {', 'g');
+ let re4rep = new RegExp('isa = PBXProject;(.|[\r\n])*TargetAttributes(.|[\r\n])*SystemCapabilities(.|[\r\n])*com\.apple\.Push = {(.|[\r\n])*enabled = [01]');
+
+ let matched = data.match(re1);
+ let result;
+ if (matched === null) {
+ console.log('re1 not match, no TargetAttributes');
+ result = data.replace(re1rep, 'isa = PBXProject;\n' +
+ '\t\t\tattributes = {\n' +
+ '\t\t\t\tTargetAttributes = {\n' +
+ '\t\t\t\t\t1D6058900D05DD3D006BFB54 = {\n' +
+ '\t\t\t\t\t\tDevelopmentTeam = ' + cordovaBuildConfig.ios.release.developmentTeam + ';\n' +
+ '\t\t\t\t\t\tSystemCapabilities = {\n' +
+ '\t\t\t\t\t\t\tcom.apple.Push = {\n' +
+ '\t\t\t\t\t\t\t\tenabled = 1;\n' +
+ '\t\t\t\t\t\t\t};\n' +
+ '\t\t\t\t\t\t};\n' +
+ '\t\t\t\t\t};\n' +
+ '\t\t\t\t};');
+ } else {
+ matched = data.match(re2);
+ if(matched === null) {
+ console.log('re2 not match, nothing under TargetAttributes');
+ let parts = re2rep.exec(data);
+ result = data.replace(re2rep, parts[0] + '\n' + '\t\t\t\t\t1D6058900D05DD3D006BFB54 = {\n' +
+ '\t\t\t\t\t\tDevelopmentTeam = ' + cordovaBuildConfig.ios.release.developmentTeam + ';\n' +
+ '\t\t\t\t\t\tSystemCapabilities = {\n' +
+ '\t\t\t\t\t\t\tcom.apple.Push = {\n' +
+ '\t\t\t\t\t\t\t\tenabled = 1;\n' +
+ '\t\t\t\t\t\t\t};\n' +
+ '\t\t\t\t\t\t};\n' +
+ '\t\t\t\t\t};');
+ } else {
+ matched = data.match(re3);
+ if(matched === null) {
+ console.log('re3 not match, no com.apple.Push defined');
+ let parts = re3rep.exec(data);
+ result = data.replace(re3rep, parts[0] + '\n' + '\t\t\t\t\t\t\tcom.apple.Push = {\n' +
+ '\t\t\t\t\t\t\t\tenabled = 1;\n' +
+ '\t\t\t\t\t\t\t};');
+ } else {
+ console.log('just enable com.apple.Push');
+ let parts = re4rep.exec(data);
+ result = data.replace(re4rep, parts[0].substr(0, parts[0].length - 1) + '1');
+ }
+ }
+ }
+
+ // add entitlements
+ if (needAddEntitlementToPbxproj) {
+
+ let pathArray = entitlementsPath.split("/");
+ let entitlementsFileName = pathArray[pathArray.length - 1];
+ let projectFolderName = pathArray[pathArray.length - 2];
+
+ result = result.replace(new RegExp('\\/\\* Begin PBXFileReference section \\*\\/'), '/* Begin PBXFileReference section */\n' +
+ '\t\tD7BB385F1E4DB54800345BF4 /* ' + entitlementsFileName + ' */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = "' + entitlementsFileName + '"; path = "' + projectFolderName + '/' + entitlementsFileName + '"; sourceTree = "<group>"; };');
+ result = result.replace(new RegExp('\\/\\* CustomTemplate \\*\\/.*\n.*isa = PBXGroup;.*\n.*children = \\('), '/* CustomTemplate */ = {\n' +
+ '\t\t\tisa = PBXGroup;\n' +
+ '\t\t\tchildren = (\n' +
+ '\t\t\t\tD7BB385F1E4DB54800345BF4 /* ' + entitlementsFileName + ' */,');
+ let re5rep = new RegExp('\\/\\* Debug \\*\\/.*\n.*isa = XCBuildConfiguration;.*\n.*\n.*buildSettings = {');
+ let parts = result.match(re5rep);
+ result = result.replace(re5rep, parts + '\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = "' + projectFolderName + '/' + entitlementsFileName + '";');
+
+ let re6rep = new RegExp('\\/\\* Release \\*\\/.*\n.*isa = XCBuildConfiguration;.*\n.*\n.*buildSettings = {');
+ parts = result.match(re6rep);
+ result = result.replace(re6rep, parts + '\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = "' + projectFolderName + '/' + entitlementsFileName + '";');
+ }
+
+ // write result to project.pbxproj
+ fs.writeFile(pbxprojPath, result, {"encoding": 'utf8'}, function(err) {
+ if (err) {
+ throw err;
+ }
+ console.log(pbxprojPath + " written successfully");
+ });
+ });
+}
+
+module.exports = (context) => {
+ let basePath = './platforms/ios/';
+ let buildType = 'dev';
+ let xcodeprojName = commonFuncs.getXcodeProjName(basePath);
+ let pbxprojPath = basePath + xcodeprojName + '.xcodeproj/project.pbxproj';
+ let entitlementsPath = basePath + xcodeprojName + '/' + xcodeprojName + '.entitlements';
+
+ let cordovaBuildConfigPath = './build.json'
+ let cordovaBuildConfig = null;
+ let willEnablePushNotificationForXCode = true;
+ try { // try to read ios developmentTeam from build.json
+ cordovaBuildConfig = JSON.parse(fs.readFileSync(cordovaBuildConfigPath, "utf8"));
+ if(cordovaBuildConfig.ios.release.developmentTeam === null && cordovaBuildConfig.ios.release.developmentTeam === undefined) {
+ throw 'no valid developmentTeam found in build.json';
+ }
+ } catch(e) {
+ console.log("Do not detected 'build.json' or ios.release.developmentTeam not avaliable in 'build.json' \n" +
+ "Will not enable XCode Push Notification Capability. \n" +
+ "Will only enable Push Notification for CI by add config to '" + basePath + xcodeprojName + "/Entitlements-Debug.plist' and '" + basePath + xcodeprojName + "/Entitlements-Release.plist' \n" +
+ "Please add 'build.json' to cordova project root folder to make after hook fully functional. \n" +
+ "Reference [1]https://cordova.apache.org/docs/en/latest/reference/cordova-cli/#cordova-build-command \n" +
+ "Reference [2]https://cordova.apache.org/docs/en/latest/guide/platforms/ios/#signing-an-app");
+ willEnablePushNotificationForXCode = false;
+ }
+
+ enablePushNotificationForCI(basePath, xcodeprojName);
+
+ if(willEnablePushNotificationForXCode) {
+ enablePushNotificationForXCode(entitlementsPath, pbxprojPath, cordovaBuildConfig);
+ }
+}
--- /dev/null
+import { Component } from '@angular/core';
+import { Platform } from 'ionic-angular';
+import { StatusBar } from '@ionic-native/status-bar';
+import { SplashScreen } from '@ionic-native/splash-screen';
+import { JPush } from '@jiguang-ionic/jpush';
+
+import { HomePage } from '../pages/home/home';
+@Component({
+ templateUrl: 'app.html'
+})
+export class MyApp {
+ rootPage:any = HomePage;
+
+ constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, jpush: JPush) {
+ platform.ready().then(() => {
+ // Okay, so the platform is ready and our plugins are available.
+ // Here you can do any higher level native things you might need.
+ statusBar.styleDefault();
+ splashScreen.hide();
+
+ jpush.init();
+ jpush.setDebugMode(true);
+ });
+ }
+}
--- /dev/null
+<ion-nav [root]="rootPage"></ion-nav>
--- /dev/null
+import { BrowserModule } from '@angular/platform-browser';
+import { ErrorHandler, NgModule } from '@angular/core';
+import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
+import { SplashScreen } from '@ionic-native/splash-screen';
+import { StatusBar } from '@ionic-native/status-bar';
+import { Device } from '@ionic-native/device';
+import { JPush } from '@jiguang-ionic/jpush';
+
+import { MyApp } from './app.component';
+import { HomePage } from '../pages/home/home';
+
+@NgModule({
+ declarations: [
+ MyApp,
+ HomePage
+ ],
+ imports: [
+ BrowserModule,
+ IonicModule.forRoot(MyApp)
+ ],
+ bootstrap: [IonicApp],
+ entryComponents: [
+ MyApp,
+ HomePage
+ ],
+ providers: [
+ StatusBar,
+ SplashScreen,
+ Device,
+ JPush,
+ {provide: ErrorHandler, useClass: IonicErrorHandler}
+ ]
+})
+export class AppModule {}
--- /dev/null
+<ion-header>
+ <ion-navbar>
+ <ion-title>
+ JPush Ionic Example
+ </ion-title>
+ </ion-navbar>
+</ion-header>
+
+<ion-content padding>
+
+ <ion-list>
+ <ion-item>
+ <div>Registration Id: {{registrationId}}</div>
+ <button ion-button full (click)="getRegistrationID()">Get Registration Id</button>
+ </ion-item>
+
+ <ion-item>
+ <button ion-button full (click)="setTags()">Set tags - Tag1, Tag2</button>
+ <button ion-button full (click)="addTags()">Add tags - Tag3, Tag4</button>
+ <button ion-button full (click)="checkTagBindState()">Check tag bind state - Tag1</button>
+ <button ion-button full (click)="deleteTags()">Delete tags - Tag4</button>
+ <button ion-button full (click)="getAllTags()">Get all tags</button>
+ <button ion-button full (click)="cleanTags()">Clean tags</button>
+ </ion-item>
+
+ <ion-item>
+ <button ion-button full (click)="setAlias()">Set Alias - TestAlias</button>
+ <button ion-button full (click)="getAlias()">Get Alias</button>
+ <button ion-button full (click)="deleteAlias()">Delete Alias</button>
+ </ion-item>
+
+ <ion-item>
+ <button ion-button full (click)="addLocalNotification()">Trigger local notification after 5 seconds</button>
+ </ion-item>
+ </ion-list>
+</ion-content>
--- /dev/null
+page-home {
+
+}
--- /dev/null
+import { Component } from "@angular/core";
+import { NavController } from "ionic-angular";
+import { JPush } from "@jiguang-ionic/jpush";
+import { Device } from "@ionic-native/device";
+
+@Component({
+ selector: "page-home",
+ templateUrl: "home.html"
+})
+export class HomePage {
+ public registrationId: string;
+
+ devicePlatform: string;
+ sequence: number = 0;
+
+ tagResultHandler = function(result) {
+ var sequence: number = result.sequence;
+ var tags: Array<string> = result.tags == null ? [] : result.tags;
+ alert(
+ "Success!" + "\nSequence: " + sequence + "\nTags: " + tags.toString()
+ );
+ };
+
+ aliasResultHandler = function(result) {
+ var sequence: number = result.sequence;
+ var alias: string = result.alias;
+ alert("Success!" + "\nSequence: " + sequence + "\nAlias: " + alias);
+ };
+
+ errorHandler = function(err) {
+ var sequence: number = err.sequence;
+ var code = err.code;
+ alert("Error!" + "\nSequence: " + sequence + "\nCode: " + code);
+ };
+
+ constructor(
+ public navCtrl: NavController,
+ public jpush: JPush,
+ device: Device
+ ) {
+ this.devicePlatform = device.platform;
+
+ document.addEventListener(
+ "jpush.receiveNotification",
+ (event: any) => {
+ var content;
+ if (this.devicePlatform == "Android") {
+ content = event.alert;
+ } else {
+ content = event.aps.alert;
+ }
+ alert("Receive notification: " + JSON.stringify(event));
+ },
+ false
+ );
+
+ document.addEventListener(
+ "jpush.openNotification",
+ (event: any) => {
+ var content;
+ if (this.devicePlatform == "Android") {
+ content = event.alert;
+ } else {
+ // iOS
+ if (event.aps == undefined) {
+ // 本地通知
+ content = event.content;
+ } else {
+ // APNS
+ content = event.aps.alert;
+ }
+ }
+ alert("open notification: " + JSON.stringify(event));
+ },
+ false
+ );
+
+ document.addEventListener(
+ "jpush.receiveLocalNotification",
+ (event: any) => {
+ // iOS(*,9) Only , iOS(10,*) 将在 jpush.openNotification 和 jpush.receiveNotification 中触发。
+ var content;
+ if (this.devicePlatform == "Android") {
+ } else {
+ content = event.content;
+ }
+ alert("receive local notification: " + JSON.stringify(event));
+ },
+ false
+ );
+ }
+
+ getRegistrationID() {
+ this.jpush.getRegistrationID().then(rId => {
+ this.registrationId = rId;
+ });
+ }
+
+ setTags() {
+ this.jpush
+ .setTags({ sequence: this.sequence++, tags: ["Tag1", "Tag2"] })
+ .then(this.tagResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ addTags() {
+ this.jpush
+ .addTags({ sequence: this.sequence++, tags: ["Tag3", "Tag4"] })
+ .then(this.tagResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ checkTagBindState() {
+ this.jpush
+ .checkTagBindState({ sequence: this.sequence++, tag: "Tag1" })
+ .then(result => {
+ var sequence = result.sequence;
+ var tag = result.tag;
+ var isBind = result.isBind;
+ alert(
+ "Sequence: " + sequence + "\nTag: " + tag + "\nIsBind: " + isBind
+ );
+ })
+ .catch(this.errorHandler);
+ }
+
+ deleteTags() {
+ this.jpush
+ .deleteTags({ sequence: this.sequence++, tags: ["Tag4"] })
+ .then(this.tagResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ getAllTags() {
+ this.jpush
+ .getAllTags({ sequence: this.sequence++ })
+ .then(this.tagResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ cleanTags() {
+ this.jpush
+ .cleanTags({ sequence: this.sequence++ })
+ .then(this.tagResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ setAlias() {
+ this.jpush
+ .setAlias({ sequence: this.sequence++, alias: "TestAlias" })
+ .then(this.aliasResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ getAlias() {
+ this.jpush
+ .getAlias({ sequence: this.sequence++ })
+ .then(this.aliasResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ deleteAlias() {
+ this.jpush
+ .deleteAlias({ sequence: this.sequence++ })
+ .then(this.aliasResultHandler)
+ .catch(this.errorHandler);
+ }
+
+ addLocalNotification() {
+ if (this.devicePlatform == "Android") {
+ this.jpush.addLocalNotification(0, "Hello JPush", "JPush", 1, 5000);
+ } else {
+ this.jpush.addLocalNotificationForIOS(5, "Hello JPush", 1, "localNoti1");
+ }
+ }
+}
--- /dev/null
+import { Plugin, Cordova, IonicNativePlugin } from '@ionic-native/core';
+import { Injectable } from '@angular/core';
+
+export interface TagOptions {
+ sequence: number;
+ tags?: Array<string>;
+}
+
+export interface AliasOptions {
+ sequence: number;
+ alias?: string;
+}
+
+@Plugin({
+ pluginName: 'JPush',
+ plugin: 'jpush-phonegap-plugin',
+ pluginRef: 'plugins.jPushPlugin',
+ repo: 'https://github.com/jpush/jpush-phonegap-plugin',
+ install: 'ionic cordova plugin add jpush-phonegap-plugin --variable APP_KEY=your_app_key',
+ installVariables: ['APP_KEY'],
+ platforms: ['Android', 'iOS']
+})
+@Injectable()
+export class JPush extends IonicNativePlugin {
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS', 'Android']
+ })
+ init(): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS', 'Android']
+ })
+ setDebugMode(enable: boolean): void { }
+
+ @Cordova()
+ getRegistrationID(): Promise<any> { return; }
+
+ @Cordova()
+ stopPush(): Promise<any> { return; }
+
+ @Cordova()
+ resumePush(): Promise<any> { return; }
+
+ @Cordova()
+ isPushStopped(): Promise<any> { return; }
+
+ @Cordova()
+ setTags(params: TagOptions): Promise<any> { return; }
+
+ @Cordova()
+ addTags(params: TagOptions): Promise<any> { return; }
+
+ @Cordova()
+ deleteTags(params: TagOptions): Promise<any> { return; }
+
+ @Cordova()
+ cleanTags(params: TagOptions): Promise<any> { return; }
+
+ @Cordova()
+ getAllTags(params: TagOptions): Promise<any> { return; }
+
+ /**
+ * @param params { sequence: number, tag: string }
+ */
+ @Cordova()
+ checkTagBindState(params: object): Promise<any> { return; }
+
+ @Cordova()
+ setAlias(params: AliasOptions): Promise<any> { return; }
+
+ @Cordova()
+ deleteAlias(params: AliasOptions): Promise<any> { return; }
+
+ @Cordova()
+ getAlias(params: AliasOptions): Promise<any> { return; }
+
+ /**
+ * Determinate whether the application notification has been opened.
+ *
+ * iOS: 0: closed; >1: opened.
+ * UIRemoteNotificationTypeNone = 0,
+ * UIRemoteNotificationTypeBadge = 1 << 0,
+ * UIRemoteNotificationTypeSound = 1 << 1,
+ * UIRemoteNotificationTypeAlert = 1 << 2,
+ * UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3
+ *
+ * Android: 0: closed; 1: opened.
+ */
+ @Cordova()
+ getUserNotificationSettings(): Promise<any> { return; }
+
+ @Cordova()
+ clearLocalNotifications(): Promise<any> { return; }
+
+ // iOS API - start
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ setBadge(badge: number): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ resetBadge(): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ setApplicationIconBadgeNumber(badge: number): void { }
+
+ @Cordova()
+ getApplicationIconBadgeNumber(): Promise<any> { return; }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ addLocalNotificationForIOS(delayTime: number, content: string, badge: number, identifierKey: string, extras?: object): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ deleteLocalNotificationWithIdentifierKeyInIOS(identifierKey: string): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ addDismissActions(actions: Array<object>, categoryId: string): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ addNotificationActions(actions: Array<object>, categoryId: string): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ setLocation(latitude: number, longitude: number): void { }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ startLogPageView(pageName: string): void { return; }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ stopLogPageView(pageName: string): void { return; }
+
+ @Cordova({
+ sync: true,
+ platforms: ['iOS']
+ })
+ beginLogPageView(pageName: string, duration: number): void { return; }
+
+ // iOS API - end
+
+ // Android API - start
+
+ @Cordova()
+ getConnectionState(): Promise<any> { return; }
+
+ @Cordova()
+ setBasicPushNotificationBuilder(): Promise<any> { return; }
+
+ @Cordova()
+ setCustomPushNotificationBuilder(): Promise<any> { return; }
+
+ @Cordova()
+ clearAllNotification(): Promise<any> { return; }
+
+ @Cordova()
+ clearNotificationById(id: number): Promise<any> { return; }
+
+ @Cordova()
+ setLatestNotificationNum(num: number): Promise<any> { return; }
+
+ @Cordova()
+ addLocalNotification(builderId: number, content: string, title: string, notificationId: number, broadcastTime: number, extras?: string): Promise<any> { return; }
+
+ @Cordova()
+ removeLocalNotification(notificationId: number): Promise<any> { return; }
+
+ @Cordova()
+ reportNotificationOpened(msgId: number): Promise<any> { return; }
+
+ @Cordova()
+ requestPermission(): Promise<any> { return; }
+
+ @Cordova()
+ setSilenceTime(startHour: number, startMinute: number, endHour: number, endMinute: number): Promise<any> { return; }
+
+ @Cordova()
+ setPushTime(weekdays: Array<string>, startHour: number, endHour: number): Promise<any> { return; }
+
+ // Android API - end
+}
--- /dev/null
+import { IonicNativePlugin } from '@ionic-native/core';
+export interface TagOptions {
+ sequence: number;
+ tags?: Array<string>;
+}
+export interface AliasOptions {
+ sequence: number;
+ alias?: string;
+}
+/**
+ * @name jpush
+ * @description
+ * This plugin does something
+ *
+ * @usage
+ * ```typescript
+ * import { jpush } from '@ionic-native/jpush';
+ *
+ *
+ * constructor(private jpush: jpush) { }
+ *
+ * ...
+ *
+ *
+ * this.jpush.functionName('Hello', 123)
+ * .then((res: any) => console.log(res))
+ * .catch((error: any) => console.error(error));
+ *
+ * ```
+ */
+export declare class JPushOriginal extends IonicNativePlugin {
+ /**
+ * This function does something
+ * @param arg1 {string} Some param to configure something
+ * @param arg2 {number} Another param to configure something
+ * @return {Promise<any>} Returns a promise that resolves when something happens
+ */
+ functionName(arg1: string, arg2: number): Promise<any>;
+ init(): void;
+ setDebugMode(enable: boolean): void;
+ getRegistrationID(): Promise<any>;
+ stopPush(): Promise<any>;
+ resumePush(): Promise<any>;
+ isPushStopped(): Promise<any>;
+ setTags(params: TagOptions): Promise<any>;
+ addTags(params: TagOptions): Promise<any>;
+ deleteTags(params: TagOptions): Promise<any>;
+ cleanTags(params: TagOptions): Promise<any>;
+ getAllTags(params: TagOptions): Promise<any>;
+ /**
+ * @param params { sequence: number, tag: string }
+ */
+ checkTagBindState(params: object): Promise<any>;
+ setAlias(params: AliasOptions): Promise<any>;
+ deleteAlias(params: AliasOptions): Promise<any>;
+ getAlias(params: AliasOptions): Promise<any>;
+ /**
+ * Determinate whether the application notification has been opened.
+ *
+ * iOS: 0: closed; >1: opened.
+ * UIRemoteNotificationTypeNone = 0,
+ * UIRemoteNotificationTypeBadge = 1 << 0,
+ * UIRemoteNotificationTypeSound = 1 << 1,
+ * UIRemoteNotificationTypeAlert = 1 << 2,
+ * UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3
+ *
+ * Android: 0: closed; 1: opened.
+ */
+ getUserNotificationSettings(): Promise<any>;
+ clearLocalNotifications(): Promise<any>;
+ setBadge(badge: number): void;
+ resetBadge(): void;
+ setApplicationIconBadgeNumber(badge: number): void;
+ getApplicationIconBadgeNumber(): Promise<any>;
+ addLocalNotificationForIOS(delayTime: number, content: string, badge: number, identifierKey: string, extras?: object): void;
+ deleteLocalNotificationWithIdentifierKeyInIOS(identifierKey: string): void;
+ addDismissActions(actions: Array<object>, categoryId: string): void;
+ addNotificationActions(actions: Array<object>, categoryId: string): void;
+ setLocation(latitude: number, longitude: number): void;
+ startLogPageView(pageName: string): void;
+ stopLogPageView(pageName: string): void;
+ beginLogPageView(pageName: string, duration: number): void;
+ getConnectionState(): Promise<any>;
+ setBasicPushNotificationBuilder(): Promise<any>;
+ setCustomPushNotificationBuilder(): Promise<any>;
+ clearAllNotification(): Promise<any>;
+ clearNotificationById(id: number): Promise<any>;
+ setLatestNotificationNum(num: number): Promise<any>;
+ addLocalNotification(builderId: number, content: string, title: string, notificationId: number, broadcastTime: number, extras?: string): Promise<any>;
+ removeLocalNotification(notificationId: number): Promise<any>;
+ reportNotificationOpened(msgId: number): Promise<any>;
+ requestPermission(): Promise<any>;
+ setSilenceTime(startHour: number, startMinute: number, endHour: number, endMinute: number): Promise<any>;
+ setPushTime(weekdays: Array<string>, startHour: number, endHour: number): Promise<any>;
+}
+
+export declare const JPush: JPushOriginal;
\ No newline at end of file
--- /dev/null
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+import { IonicNativePlugin, cordova } from '@ionic-native/core';
+var JPushOriginal = /** @class */ (function (_super) {
+ __extends(JPushOriginal, _super);
+ function JPushOriginal() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ JPushOriginal.prototype.functionName = function (arg1, arg2) { return cordova(this, "functionName", {}, arguments); };
+ JPushOriginal.prototype.init = function () { return cordova(this, "init", { "sync": true, "platforms": ["iOS", "Android"] }, arguments); };
+ JPushOriginal.prototype.setDebugMode = function (enable) { return cordova(this, "setDebugMode", { "sync": true, "platforms": ["iOS", "Android"] }, arguments); };
+ JPushOriginal.prototype.getRegistrationID = function () { return cordova(this, "getRegistrationID", {}, arguments); };
+ JPushOriginal.prototype.stopPush = function () { return cordova(this, "stopPush", {}, arguments); };
+ JPushOriginal.prototype.resumePush = function () { return cordova(this, "resumePush", {}, arguments); };
+ JPushOriginal.prototype.isPushStopped = function () { return cordova(this, "isPushStopped", {}, arguments); };
+ JPushOriginal.prototype.setTags = function (params) { return cordova(this, "setTags", {}, arguments); };
+ JPushOriginal.prototype.addTags = function (params) { return cordova(this, "addTags", {}, arguments); };
+ JPushOriginal.prototype.deleteTags = function (params) { return cordova(this, "deleteTags", {}, arguments); };
+ JPushOriginal.prototype.cleanTags = function (params) { return cordova(this, "cleanTags", {}, arguments); };
+ JPushOriginal.prototype.getAllTags = function (params) { return cordova(this, "getAllTags", {}, arguments); };
+ JPushOriginal.prototype.checkTagBindState = function (params) { return cordova(this, "checkTagBindState", {}, arguments); };
+ JPushOriginal.prototype.setAlias = function (params) { return cordova(this, "setAlias", {}, arguments); };
+ JPushOriginal.prototype.deleteAlias = function (params) { return cordova(this, "deleteAlias", {}, arguments); };
+ JPushOriginal.prototype.getAlias = function (params) { return cordova(this, "getAlias", {}, arguments); };
+ JPushOriginal.prototype.getUserNotificationSettings = function () { return cordova(this, "getUserNotificationSettings", {}, arguments); };
+ JPushOriginal.prototype.clearLocalNotifications = function () { return cordova(this, "clearLocalNotifications", {}, arguments); };
+ JPushOriginal.prototype.setBadge = function (badge) { return cordova(this, "setBadge", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.resetBadge = function () { return cordova(this, "resetBadge", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.setApplicationIconBadgeNumber = function (badge) { return cordova(this, "setApplicationIconBadgeNumber", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.getApplicationIconBadgeNumber = function () { return cordova(this, "getApplicationIconBadgeNumber", {}, arguments); };
+ JPushOriginal.prototype.addLocalNotificationForIOS = function (delayTime, content, badge, identifierKey, extras) { return cordova(this, "addLocalNotificationForIOS", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function (identifierKey) { return cordova(this, "deleteLocalNotificationWithIdentifierKeyInIOS", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.addDismissActions = function (actions, categoryId) { return cordova(this, "addDismissActions", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.addNotificationActions = function (actions, categoryId) { return cordova(this, "addNotificationActions", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.setLocation = function (latitude, longitude) { return cordova(this, "setLocation", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.startLogPageView = function (pageName) { return cordova(this, "startLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.stopLogPageView = function (pageName) { return cordova(this, "stopLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.beginLogPageView = function (pageName, duration) { return cordova(this, "beginLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPushOriginal.prototype.getConnectionState = function () { return cordova(this, "getConnectionState", {}, arguments); };
+ JPushOriginal.prototype.setBasicPushNotificationBuilder = function () { return cordova(this, "setBasicPushNotificationBuilder", {}, arguments); };
+ JPushOriginal.prototype.setCustomPushNotificationBuilder = function () { return cordova(this, "setCustomPushNotificationBuilder", {}, arguments); };
+ JPushOriginal.prototype.clearAllNotification = function () { return cordova(this, "clearAllNotification", {}, arguments); };
+ JPushOriginal.prototype.clearNotificationById = function (id) { return cordova(this, "clearNotificationById", {}, arguments); };
+ JPushOriginal.prototype.setLatestNotificationNum = function (num) { return cordova(this, "setLatestNotificationNum", {}, arguments); };
+ JPushOriginal.prototype.addLocalNotification = function (builderId, content, title, notificationId, broadcastTime, extras) { return cordova(this, "addLocalNotification", {}, arguments); };
+ JPushOriginal.prototype.removeLocalNotification = function (notificationId) { return cordova(this, "removeLocalNotification", {}, arguments); };
+ JPushOriginal.prototype.reportNotificationOpened = function (msgId) { return cordova(this, "reportNotificationOpened", {}, arguments); };
+ JPushOriginal.prototype.requestPermission = function () { return cordova(this, "requestPermission", {}, arguments); };
+ JPushOriginal.prototype.setSilenceTime = function (startHour, startMinute, endHour, endMinute) { return cordova(this, "setSilenceTime", {}, arguments); };
+ JPushOriginal.prototype.setPushTime = function (weekdays, startHour, endHour) { return cordova(this, "setPushTime", {}, arguments); };
+ JPushOriginal.pluginName = "JPush";
+ JPushOriginal.plugin = "jpush-phonegap-plugin";
+ JPushOriginal.pluginRef = "plugins.jPushPlugin";
+ JPushOriginal.repo = "https://github.com/jpush/jpush-phonegap-plugin";
+ JPushOriginal.install = "ionic cordova plugin add jpush-phonegap-plugin --variable APP_KEY=your_app_key";
+ JPushOriginal.installVariables = ["APP_KEY"];
+ JPushOriginal.platforms = ["Android", "iOS"];
+ return JPushOriginal;
+}(IonicNativePlugin));
+var JPush = new JPushOriginal();
+export { JPush };
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvQGlvbmljLW5hdGl2ZS9wbHVnaW5zL2pwdXNoL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFZQSxPQUFPLDhCQUEwRixNQUFNLG9CQUFvQixDQUFDOztJQXVEakcseUJBQWlCOzs7O0lBUzFDLDRCQUFZLGFBQUMsSUFBWSxFQUFFLElBQVk7SUFRdkMsb0JBQUk7SUFNSiw0QkFBWSxhQUFDLE1BQWU7SUFHNUIsaUNBQWlCO0lBR2pCLHdCQUFRO0lBR1IsMEJBQVU7SUFHViw2QkFBYTtJQUdiLHVCQUFPLGFBQUMsTUFBa0I7SUFHMUIsdUJBQU8sYUFBQyxNQUFrQjtJQUcxQiwwQkFBVSxhQUFDLE1BQWtCO0lBRzdCLHlCQUFTLGFBQUMsTUFBa0I7SUFHNUIsMEJBQVUsYUFBQyxNQUFrQjtJQU03QixpQ0FBaUIsYUFBQyxNQUFjO0lBR2hDLHdCQUFRLGFBQUMsTUFBb0I7SUFHN0IsMkJBQVcsYUFBQyxNQUFvQjtJQUdoQyx3QkFBUSxhQUFDLE1BQW9CO0lBZTdCLDJDQUEyQjtJQUczQix1Q0FBdUI7SUFRdkIsd0JBQVEsYUFBQyxLQUFhO0lBTXRCLDBCQUFVO0lBTVYsNkNBQTZCLGFBQUMsS0FBYTtJQUczQyw2Q0FBNkI7SUFNN0IsMENBQTBCLGFBQUMsU0FBaUIsRUFBRSxPQUFlLEVBQUUsS0FBYSxFQUFFLGFBQXFCLEVBQUUsTUFBZTtJQU1wSCw2REFBNkMsYUFBQyxhQUFxQjtJQU1uRSxpQ0FBaUIsYUFBQyxPQUFzQixFQUFFLFVBQWtCO0lBTTVELHNDQUFzQixhQUFDLE9BQXNCLEVBQUUsVUFBa0I7SUFNakUsMkJBQVcsYUFBQyxRQUFnQixFQUFFLFNBQWlCO0lBTS9DLGdDQUFnQixhQUFDLFFBQWdCO0lBTWpDLCtCQUFlLGFBQUMsUUFBZ0I7SUFNaEMsZ0NBQWdCLGFBQUMsUUFBZ0IsRUFBRSxRQUFnQjtJQU9uRCxrQ0FBa0I7SUFHbEIsK0NBQStCO0lBRy9CLGdEQUFnQztJQUdoQyxvQ0FBb0I7SUFHcEIscUNBQXFCLGFBQUMsRUFBVTtJQUdoQyx3Q0FBd0IsYUFBQyxHQUFXO0lBR3BDLG9DQUFvQixhQUFDLFNBQWlCLEVBQUUsT0FBZSxFQUFFLEtBQWEsRUFBRSxjQUFzQixFQUFFLGFBQXFCLEVBQUUsTUFBZTtJQUd0SSx1Q0FBdUIsYUFBQyxjQUFzQjtJQUc5Qyx3Q0FBd0IsYUFBQyxLQUFhO0lBR3RDLGlDQUFpQjtJQUdqQiw4QkFBYyxhQUFDLFNBQWlCLEVBQUUsV0FBbUIsRUFBRSxPQUFlLEVBQUUsU0FBaUI7SUFHekYsMkJBQVcsYUFBQyxRQUF1QixFQUFFLFNBQWlCLEVBQUUsT0FBZTs7Ozs7Ozs7Z0JBclF6RTtFQW1FMkIsaUJBQWlCO1NBQS9CLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRoaXMgaXMgYSB0ZW1wbGF0ZSBmb3IgbmV3IHBsdWdpbiB3cmFwcGVyc1xuICpcbiAqIFRPRE86XG4gKiAtIEFkZC9DaGFuZ2UgaW5mb3JtYXRpb24gYmVsb3dcbiAqIC0gRG9jdW1lbnQgdXNhZ2UgKGltcG9ydGluZywgZXhlY3V0aW5nIG1haW4gZnVuY3Rpb25hbGl0eSlcbiAqIC0gUmVtb3ZlIGFueSBpbXBvcnRzIHRoYXQgeW91IGFyZSBub3QgdXNpbmdcbiAqIC0gUmVtb3ZlIGFsbCB0aGUgY29tbWVudHMgaW5jbHVkZWQgaW4gdGhpcyB0ZW1wbGF0ZSwgRVhDRVBUIHRoZSBAUGx1Z2luIHdyYXBwZXIgZG9jcyBhbmQgYW55IG90aGVyIGRvY3MgeW91IGFkZGVkXG4gKiAtIFJlbW92ZSB0aGlzIG5vdGVcbiAqXG4gKi9cbmltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFBsdWdpbiwgQ29yZG92YSwgQ29yZG92YVByb3BlcnR5LCBDb3Jkb3ZhSW5zdGFuY2UsIEluc3RhbmNlUHJvcGVydHksIElvbmljTmF0aXZlUGx1Z2luIH0gZnJvbSAnQGlvbmljLW5hdGl2ZS9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuZXhwb3J0IGludGVyZmFjZSBUYWdPcHRpb25zIHtcbiAgc2VxdWVuY2U6IG51bWJlcjtcbiAgdGFncz86IEFycmF5PHN0cmluZz47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQWxpYXNPcHRpb25zIHtcbiAgc2VxdWVuY2U6IG51bWJlcjtcbiAgYWxpYXM/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQG5hbWUganB1c2hcbiAqIEBkZXNjcmlwdGlvblxuICogVGhpcyBwbHVnaW4gZG9lcyBzb21ldGhpbmdcbiAqXG4gKiBAdXNhZ2VcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGltcG9ydCB7IGpwdXNoIH0gZnJvbSAnQGlvbmljLW5hdGl2ZS9qcHVzaCc7XG4gKlxuICpcbiAqIGNvbnN0cnVjdG9yKHByaXZhdGUganB1c2g6IGpwdXNoKSB7IH1cbiAqXG4gKiAuLi5cbiAqXG4gKlxuICogdGhpcy5qcHVzaC5mdW5jdGlvbk5hbWUoJ0hlbGxvJywgMTIzKVxuICogICAudGhlbigocmVzOiBhbnkpID0+IGNvbnNvbGUubG9nKHJlcykpXG4gKiAgIC5jYXRjaCgoZXJyb3I6IGFueSkgPT4gY29uc29sZS5lcnJvcihlcnJvcikpO1xuICpcbiAqIGBgYFxuICovXG4vLyBAUGx1Z2luKHtcbi8vICAgcGx1Z2luTmFtZTogJ2pwdXNoJyxcbi8vICAgcGx1Z2luOiAnJywgLy8gbnBtIHBhY2thZ2UgbmFtZSwgZXhhbXBsZTogY29yZG92YS1wbHVnaW4tY2FtZXJhXG4vLyAgIHBsdWdpblJlZjogJycsIC8vIHRoZSB2YXJpYWJsZSByZWZlcmVuY2UgdG8gY2FsbCB0aGUgcGx1Z2luLCBleGFtcGxlOiBuYXZpZ2F0b3IuZ2VvbG9jYXRpb25cbi8vICAgcmVwbzogJycsIC8vIHRoZSBnaXRodWIgcmVwb3NpdG9yeSBVUkwgZm9yIHRoZSBwbHVnaW5cbi8vICAgaW5zdGFsbDogJycsIC8vIE9QVElPTkFMIGluc3RhbGwgY29tbWFuZCwgaW4gY2FzZSB0aGUgcGx1Z2luIHJlcXVpcmVzIHZhcmlhYmxlc1xuLy8gICBpbnN0YWxsVmFyaWFibGVzOiBbXSwgLy8gT1BUSU9OQUwgdGhlIHBsdWdpbiByZXF1aXJlcyB2YXJpYWJsZXNcbi8vICAgcGxhdGZvcm1zOiBbXSAvLyBBcnJheSBvZiBwbGF0Zm9ybXMgc3VwcG9ydGVkLCBleGFtcGxlOiBbJ0FuZHJvaWQnLCAnaU9TJ11cbi8vIH0pXG5AUGx1Z2luKHtcbiAgcGx1Z2luTmFtZTogJ0pQdXNoJyxcbiAgcGx1Z2luOiAnanB1c2gtcGhvbmVnYXAtcGx1Z2luJyxcbiAgcGx1Z2luUmVmOiAncGx1Z2lucy5qUHVzaFBsdWdpbicsXG4gIHJlcG86ICdodHRwczovL2dpdGh1Yi5jb20vanB1c2gvanB1c2gtcGhvbmVnYXAtcGx1Z2luJyxcbiAgaW5zdGFsbDogJ2lvbmljIGNvcmRvdmEgcGx1Z2luIGFkZCBqcHVzaC1waG9uZWdhcC1wbHVnaW4gLS12YXJpYWJsZSBBUFBfS0VZPXlvdXJfYXBwX2tleScsXG4gIGluc3RhbGxWYXJpYWJsZXM6IFsnQVBQX0tFWSddLFxuICBwbGF0Zm9ybXM6IFsnQW5kcm9pZCcsICdpT1MnXVxufSlcbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEpQdXNoIGV4dGVuZHMgSW9uaWNOYXRpdmVQbHVnaW4ge1xuXG4gIC8qKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGRvZXMgc29tZXRoaW5nXG4gICAqIEBwYXJhbSBhcmcxIHtzdHJpbmd9IFNvbWUgcGFyYW0gdG8gY29uZmlndXJlIHNvbWV0aGluZ1xuICAgKiBAcGFyYW0gYXJnMiB7bnVtYmVyfSBBbm90aGVyIHBhcmFtIHRvIGNvbmZpZ3VyZSBzb21ldGhpbmdcbiAgICogQHJldHVybiB7UHJvbWlzZTxhbnk+fSBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gc29tZXRoaW5nIGhhcHBlbnNcbiAgICovXG4gIEBDb3Jkb3ZhKClcbiAgZnVuY3Rpb25OYW1lKGFyZzE6IHN0cmluZywgYXJnMjogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm47IC8vIFdlIGFkZCByZXR1cm47IGhlcmUgdG8gYXZvaWQgYW55IElERSAvIENvbXBpbGVyIGVycm9yc1xuICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUycsICdBbmRyb2lkJ11cbiAgIH0pXG4gIGluaXQoKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUycsICdBbmRyb2lkJ11cbiAgIH0pXG4gIHNldERlYnVnTW9kZShlbmFibGU6IGJvb2xlYW4pOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSgpXG4gIGdldFJlZ2lzdHJhdGlvbklEKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgc3RvcFB1c2goKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICByZXN1bWVQdXNoKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgaXNQdXNoU3RvcHBlZCgpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldFRhZ3MocGFyYW1zOiBUYWdPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBhZGRUYWdzKHBhcmFtczogVGFnT3B0aW9ucyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgZGVsZXRlVGFncyhwYXJhbXM6IFRhZ09wdGlvbnMpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGNsZWFuVGFncyhwYXJhbXM6IFRhZ09wdGlvbnMpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGdldEFsbFRhZ3MocGFyYW1zOiBUYWdPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSBwYXJhbXMgeyBzZXF1ZW5jZTogbnVtYmVyLCB0YWc6IHN0cmluZyB9XG4gICAqL1xuICBAQ29yZG92YSgpXG4gIGNoZWNrVGFnQmluZFN0YXRlKHBhcmFtczogb2JqZWN0KTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBzZXRBbGlhcyhwYXJhbXM6IEFsaWFzT3B0aW9ucyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgZGVsZXRlQWxpYXMocGFyYW1zOiBBbGlhc09wdGlvbnMpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGdldEFsaWFzKHBhcmFtczogQWxpYXNPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgLyoqXG4gICAqIERldGVybWluYXRlIHdoZXRoZXIgdGhlIGFwcGxpY2F0aW9uIG5vdGlmaWNhdGlvbiBoYXMgYmVlbiBvcGVuZWQuXG4gICAqIFxuICAgKiBpT1M6IDA6IGNsb3NlZDsgPjE6IG9wZW5lZC5cbiAgICogIFVJUmVtb3RlTm90aWZpY2F0aW9uVHlwZU5vbmUgPSAwLFxuICAgKiAgVUlSZW1vdGVOb3RpZmljYXRpb25UeXBlQmFkZ2UgPSAxIDw8IDAsXG4gICAqICBVSVJlbW90ZU5vdGlmaWNhdGlvblR5cGVTb3VuZCA9IDEgPDwgMSxcbiAgICogIFVJUmVtb3RlTm90aWZpY2F0aW9uVHlwZUFsZXJ0ID0gMSA8PCAyLFxuICAgKiAgVUlSZW1vdGVOb3RpZmljYXRpb25UeXBlTmV3c3N0YW5kQ29udGVudEF2YWlsYWJpbGl0eSA9IDEgPDwgM1xuICAgKiBcbiAgICogQW5kcm9pZDogMDogY2xvc2VkOyAxOiBvcGVuZWQuXG4gICAqL1xuICBAQ29yZG92YSgpXG4gIGdldFVzZXJOb3RpZmljYXRpb25TZXR0aW5ncygpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGNsZWFyTG9jYWxOb3RpZmljYXRpb25zKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIC8vIGlPUyBBUEkgLSBzdGFydFxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgc2V0QmFkZ2UoYmFkZ2U6IG51bWJlcik6IHZvaWQgeyAgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgcmVzZXRCYWRnZSgpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIHNldEFwcGxpY2F0aW9uSWNvbkJhZGdlTnVtYmVyKGJhZGdlOiBudW1iZXIpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSgpXG4gIGdldEFwcGxpY2F0aW9uSWNvbkJhZGdlTnVtYmVyKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgYWRkTG9jYWxOb3RpZmljYXRpb25Gb3JJT1MoZGVsYXlUaW1lOiBudW1iZXIsIGNvbnRlbnQ6IHN0cmluZywgYmFkZ2U6IG51bWJlciwgaWRlbnRpZmllcktleTogc3RyaW5nLCBleHRyYXM/OiBvYmplY3QpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIGRlbGV0ZUxvY2FsTm90aWZpY2F0aW9uV2l0aElkZW50aWZpZXJLZXlJbklPUyhpZGVudGlmaWVyS2V5OiBzdHJpbmcpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIGFkZERpc21pc3NBY3Rpb25zKGFjdGlvbnM6IEFycmF5PG9iamVjdD4sIGNhdGVnb3J5SWQ6IHN0cmluZyk6IHZvaWQgeyAgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgYWRkTm90aWZpY2F0aW9uQWN0aW9ucyhhY3Rpb25zOiBBcnJheTxvYmplY3Q+LCBjYXRlZ29yeUlkOiBzdHJpbmcpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIHNldExvY2F0aW9uKGxhdGl0dWRlOiBudW1iZXIsIGxvbmdpdHVkZTogbnVtYmVyKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBzdGFydExvZ1BhZ2VWaWV3KHBhZ2VOYW1lOiBzdHJpbmcpOiB2b2lkIHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBzdG9wTG9nUGFnZVZpZXcocGFnZU5hbWU6IHN0cmluZyk6IHZvaWQgeyByZXR1cm47IH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIGJlZ2luTG9nUGFnZVZpZXcocGFnZU5hbWU6IHN0cmluZywgZHVyYXRpb246IG51bWJlcik6IHZvaWQgeyByZXR1cm47IH1cblxuICAvLyBpT1MgQVBJIC0gZW5kXG5cbiAgLy8gQW5kcm9pZCBBUEkgLSBzdGFydFxuXG4gIEBDb3Jkb3ZhKClcbiAgZ2V0Q29ubmVjdGlvblN0YXRlKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgc2V0QmFzaWNQdXNoTm90aWZpY2F0aW9uQnVpbGRlcigpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldEN1c3RvbVB1c2hOb3RpZmljYXRpb25CdWlsZGVyKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgY2xlYXJBbGxOb3RpZmljYXRpb24oKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBjbGVhck5vdGlmaWNhdGlvbkJ5SWQoaWQ6IG51bWJlcik6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgc2V0TGF0ZXN0Tm90aWZpY2F0aW9uTnVtKG51bTogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBhZGRMb2NhbE5vdGlmaWNhdGlvbihidWlsZGVySWQ6IG51bWJlciwgY29udGVudDogc3RyaW5nLCB0aXRsZTogc3RyaW5nLCBub3RpZmljYXRpb25JZDogbnVtYmVyLCBicm9hZGNhc3RUaW1lOiBudW1iZXIsIGV4dHJhcz86IHN0cmluZyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgcmVtb3ZlTG9jYWxOb3RpZmljYXRpb24obm90aWZpY2F0aW9uSWQ6IG51bWJlcik6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgcmVwb3J0Tm90aWZpY2F0aW9uT3BlbmVkKG1zZ0lkOiBudW1iZXIpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHJlcXVlc3RQZXJtaXNzaW9uKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgc2V0U2lsZW5jZVRpbWUoc3RhcnRIb3VyOiBudW1iZXIsIHN0YXJ0TWludXRlOiBudW1iZXIsIGVuZEhvdXI6IG51bWJlciwgZW5kTWludXRlOiBudW1iZXIpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldFB1c2hUaW1lKHdlZWtkYXlzOiBBcnJheTxzdHJpbmc+LCBzdGFydEhvdXI6IG51bWJlciwgZW5kSG91cjogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgLy8gQW5kcm9pZCBBUEkgLSBlbmRcblxufVxuIl19
\ No newline at end of file
--- /dev/null
+import { IonicNativePlugin } from '@ionic-native/core';
+export interface TagOptions {
+ sequence: number;
+ tags?: Array<string>;
+}
+export interface AliasOptions {
+ sequence: number;
+ alias?: string;
+}
+/**
+ * @name jpush
+ * @description
+ * This plugin does something
+ *
+ * @usage
+ * ```typescript
+ * import { jpush } from '@ionic-native/jpush';
+ *
+ *
+ * constructor(private jpush: jpush) { }
+ *
+ * ...
+ *
+ *
+ * this.jpush.functionName('Hello', 123)
+ * .then((res: any) => console.log(res))
+ * .catch((error: any) => console.error(error));
+ *
+ * ```
+ */
+export declare class JPush extends IonicNativePlugin {
+ /**
+ * This function does something
+ * @param arg1 {string} Some param to configure something
+ * @param arg2 {number} Another param to configure something
+ * @return {Promise<any>} Returns a promise that resolves when something happens
+ */
+ functionName(arg1: string, arg2: number): Promise<any>;
+ init(): void;
+ setDebugMode(enable: boolean): void;
+ getRegistrationID(): Promise<any>;
+ stopPush(): Promise<any>;
+ resumePush(): Promise<any>;
+ isPushStopped(): Promise<any>;
+ setTags(params: TagOptions): Promise<any>;
+ addTags(params: TagOptions): Promise<any>;
+ deleteTags(params: TagOptions): Promise<any>;
+ cleanTags(params: TagOptions): Promise<any>;
+ getAllTags(params: TagOptions): Promise<any>;
+ /**
+ * @param params { sequence: number, tag: string }
+ */
+ checkTagBindState(params: object): Promise<any>;
+ setAlias(params: AliasOptions): Promise<any>;
+ deleteAlias(params: AliasOptions): Promise<any>;
+ getAlias(params: AliasOptions): Promise<any>;
+ /**
+ * Determinate whether the application notification has been opened.
+ *
+ * iOS: 0: closed; >1: opened.
+ * UIRemoteNotificationTypeNone = 0,
+ * UIRemoteNotificationTypeBadge = 1 << 0,
+ * UIRemoteNotificationTypeSound = 1 << 1,
+ * UIRemoteNotificationTypeAlert = 1 << 2,
+ * UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3
+ *
+ * Android: 0: closed; 1: opened.
+ */
+ getUserNotificationSettings(): Promise<any>;
+ clearLocalNotifications(): Promise<any>;
+ setBadge(badge: number): void;
+ resetBadge(): void;
+ setApplicationIconBadgeNumber(badge: number): void;
+ getApplicationIconBadgeNumber(): Promise<any>;
+ addLocalNotificationForIOS(delayTime: number, content: string, badge: number, identifierKey: string, extras?: object): void;
+ deleteLocalNotificationWithIdentifierKeyInIOS(identifierKey: string): void;
+ addDismissActions(actions: Array<object>, categoryId: string): void;
+ addNotificationActions(actions: Array<object>, categoryId: string): void;
+ setLocation(latitude: number, longitude: number): void;
+ startLogPageView(pageName: string): void;
+ stopLogPageView(pageName: string): void;
+ beginLogPageView(pageName: string, duration: number): void;
+ getConnectionState(): Promise<any>;
+ setBasicPushNotificationBuilder(): Promise<any>;
+ setCustomPushNotificationBuilder(): Promise<any>;
+ clearAllNotification(): Promise<any>;
+ clearNotificationById(id: number): Promise<any>;
+ setLatestNotificationNum(num: number): Promise<any>;
+ addLocalNotification(builderId: number, content: string, title: string, notificationId: number, broadcastTime: number, extras?: string): Promise<any>;
+ removeLocalNotification(notificationId: number): Promise<any>;
+ reportNotificationOpened(msgId: number): Promise<any>;
+ requestPermission(): Promise<any>;
+ setSilenceTime(startHour: number, startMinute: number, endHour: number, endMinute: number): Promise<any>;
+ setPushTime(weekdays: Array<string>, startHour: number, endHour: number): Promise<any>;
+}
--- /dev/null
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+/**
+ * This is a template for new plugin wrappers
+ *
+ * TODO:
+ * - Add/Change information below
+ * - Document usage (importing, executing main functionality)
+ * - Remove any imports that you are not using
+ * - Remove all the comments included in this template, EXCEPT the @Plugin wrapper docs and any other docs you added
+ * - Remove this note
+ *
+ */
+import { Injectable } from '@angular/core';
+import { IonicNativePlugin, cordova } from '@ionic-native/core';
+var JPush = /** @class */ (function (_super) {
+ __extends(JPush, _super);
+ function JPush() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ JPush.prototype.functionName = function (arg1, arg2) { return cordova(this, "functionName", {}, arguments); };
+ JPush.prototype.init = function () { return cordova(this, "init", { "sync": true, "platforms": ["iOS", "Android"] }, arguments); };
+ JPush.prototype.setDebugMode = function (enable) { return cordova(this, "setDebugMode", { "sync": true, "platforms": ["iOS", "Android"] }, arguments); };
+ JPush.prototype.getRegistrationID = function () { return cordova(this, "getRegistrationID", {}, arguments); };
+ JPush.prototype.stopPush = function () { return cordova(this, "stopPush", {}, arguments); };
+ JPush.prototype.resumePush = function () { return cordova(this, "resumePush", {}, arguments); };
+ JPush.prototype.isPushStopped = function () { return cordova(this, "isPushStopped", {}, arguments); };
+ JPush.prototype.setTags = function (params) { return cordova(this, "setTags", {}, arguments); };
+ JPush.prototype.addTags = function (params) { return cordova(this, "addTags", {}, arguments); };
+ JPush.prototype.deleteTags = function (params) { return cordova(this, "deleteTags", {}, arguments); };
+ JPush.prototype.cleanTags = function (params) { return cordova(this, "cleanTags", {}, arguments); };
+ JPush.prototype.getAllTags = function (params) { return cordova(this, "getAllTags", {}, arguments); };
+ JPush.prototype.checkTagBindState = function (params) { return cordova(this, "checkTagBindState", {}, arguments); };
+ JPush.prototype.setAlias = function (params) { return cordova(this, "setAlias", {}, arguments); };
+ JPush.prototype.deleteAlias = function (params) { return cordova(this, "deleteAlias", {}, arguments); };
+ JPush.prototype.getAlias = function (params) { return cordova(this, "getAlias", {}, arguments); };
+ JPush.prototype.getUserNotificationSettings = function () { return cordova(this, "getUserNotificationSettings", {}, arguments); };
+ JPush.prototype.clearLocalNotifications = function () { return cordova(this, "clearLocalNotifications", {}, arguments); };
+ JPush.prototype.setBadge = function (badge) { return cordova(this, "setBadge", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.resetBadge = function () { return cordova(this, "resetBadge", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.setApplicationIconBadgeNumber = function (badge) { return cordova(this, "setApplicationIconBadgeNumber", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.getApplicationIconBadgeNumber = function () { return cordova(this, "getApplicationIconBadgeNumber", {}, arguments); };
+ JPush.prototype.addLocalNotificationForIOS = function (delayTime, content, badge, identifierKey, extras) { return cordova(this, "addLocalNotificationForIOS", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function (identifierKey) { return cordova(this, "deleteLocalNotificationWithIdentifierKeyInIOS", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.addDismissActions = function (actions, categoryId) { return cordova(this, "addDismissActions", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.addNotificationActions = function (actions, categoryId) { return cordova(this, "addNotificationActions", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.setLocation = function (latitude, longitude) { return cordova(this, "setLocation", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.startLogPageView = function (pageName) { return cordova(this, "startLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.stopLogPageView = function (pageName) { return cordova(this, "stopLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.beginLogPageView = function (pageName, duration) { return cordova(this, "beginLogPageView", { "sync": true, "platforms": ["iOS"] }, arguments); };
+ JPush.prototype.getConnectionState = function () { return cordova(this, "getConnectionState", {}, arguments); };
+ JPush.prototype.setBasicPushNotificationBuilder = function () { return cordova(this, "setBasicPushNotificationBuilder", {}, arguments); };
+ JPush.prototype.setCustomPushNotificationBuilder = function () { return cordova(this, "setCustomPushNotificationBuilder", {}, arguments); };
+ JPush.prototype.clearAllNotification = function () { return cordova(this, "clearAllNotification", {}, arguments); };
+ JPush.prototype.clearNotificationById = function (id) { return cordova(this, "clearNotificationById", {}, arguments); };
+ JPush.prototype.setLatestNotificationNum = function (num) { return cordova(this, "setLatestNotificationNum", {}, arguments); };
+ JPush.prototype.addLocalNotification = function (builderId, content, title, notificationId, broadcastTime, extras) { return cordova(this, "addLocalNotification", {}, arguments); };
+ JPush.prototype.removeLocalNotification = function (notificationId) { return cordova(this, "removeLocalNotification", {}, arguments); };
+ JPush.prototype.reportNotificationOpened = function (msgId) { return cordova(this, "reportNotificationOpened", {}, arguments); };
+ JPush.prototype.requestPermission = function () { return cordova(this, "requestPermission", {}, arguments); };
+ JPush.prototype.setSilenceTime = function (startHour, startMinute, endHour, endMinute) { return cordova(this, "setSilenceTime", {}, arguments); };
+ JPush.prototype.setPushTime = function (weekdays, startHour, endHour) { return cordova(this, "setPushTime", {}, arguments); };
+ JPush.pluginName = "JPush";
+ JPush.plugin = "jpush-phonegap-plugin";
+ JPush.pluginRef = "plugins.jPushPlugin";
+ JPush.repo = "https://github.com/jpush/jpush-phonegap-plugin";
+ JPush.install = "ionic cordova plugin add jpush-phonegap-plugin --variable APP_KEY=your_app_key";
+ JPush.installVariables = ["APP_KEY"];
+ JPush.platforms = ["Android", "iOS"];
+ JPush = __decorate([
+ Injectable({
+ providedIn: 'root'
+ })
+ ], JPush);
+ return JPush;
+}(IonicNativePlugin));
+export { JPush };
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvQGlvbmljLW5hdGl2ZS9wbHVnaW5zL2pwdXNoL25neC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7Ozs7Ozs7Ozs7R0FVRztBQUNILE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyw4QkFBMEYsTUFBTSxvQkFBb0IsQ0FBQzs7SUF1RGpHLHlCQUFpQjs7OztJQVMxQyw0QkFBWSxhQUFDLElBQVksRUFBRSxJQUFZO0lBUXZDLG9CQUFJO0lBTUosNEJBQVksYUFBQyxNQUFlO0lBRzVCLGlDQUFpQjtJQUdqQix3QkFBUTtJQUdSLDBCQUFVO0lBR1YsNkJBQWE7SUFHYix1QkFBTyxhQUFDLE1BQWtCO0lBRzFCLHVCQUFPLGFBQUMsTUFBa0I7SUFHMUIsMEJBQVUsYUFBQyxNQUFrQjtJQUc3Qix5QkFBUyxhQUFDLE1BQWtCO0lBRzVCLDBCQUFVLGFBQUMsTUFBa0I7SUFNN0IsaUNBQWlCLGFBQUMsTUFBYztJQUdoQyx3QkFBUSxhQUFDLE1BQW9CO0lBRzdCLDJCQUFXLGFBQUMsTUFBb0I7SUFHaEMsd0JBQVEsYUFBQyxNQUFvQjtJQWU3QiwyQ0FBMkI7SUFHM0IsdUNBQXVCO0lBUXZCLHdCQUFRLGFBQUMsS0FBYTtJQU10QiwwQkFBVTtJQU1WLDZDQUE2QixhQUFDLEtBQWE7SUFHM0MsNkNBQTZCO0lBTTdCLDBDQUEwQixhQUFDLFNBQWlCLEVBQUUsT0FBZSxFQUFFLEtBQWEsRUFBRSxhQUFxQixFQUFFLE1BQWU7SUFNcEgsNkRBQTZDLGFBQUMsYUFBcUI7SUFNbkUsaUNBQWlCLGFBQUMsT0FBc0IsRUFBRSxVQUFrQjtJQU01RCxzQ0FBc0IsYUFBQyxPQUFzQixFQUFFLFVBQWtCO0lBTWpFLDJCQUFXLGFBQUMsUUFBZ0IsRUFBRSxTQUFpQjtJQU0vQyxnQ0FBZ0IsYUFBQyxRQUFnQjtJQU1qQywrQkFBZSxhQUFDLFFBQWdCO0lBTWhDLGdDQUFnQixhQUFDLFFBQWdCLEVBQUUsUUFBZ0I7SUFPbkQsa0NBQWtCO0lBR2xCLCtDQUErQjtJQUcvQixnREFBZ0M7SUFHaEMsb0NBQW9CO0lBR3BCLHFDQUFxQixhQUFDLEVBQVU7SUFHaEMsd0NBQXdCLGFBQUMsR0FBVztJQUdwQyxvQ0FBb0IsYUFBQyxTQUFpQixFQUFFLE9BQWUsRUFBRSxLQUFhLEVBQUUsY0FBc0IsRUFBRSxhQUFxQixFQUFFLE1BQWU7SUFHdEksdUNBQXVCLGFBQUMsY0FBc0I7SUFHOUMsd0NBQXdCLGFBQUMsS0FBYTtJQUd0QyxpQ0FBaUI7SUFHakIsOEJBQWMsYUFBQyxTQUFpQixFQUFFLFdBQW1CLEVBQUUsT0FBZSxFQUFFLFNBQWlCO0lBR3pGLDJCQUFXLGFBQUMsUUFBdUIsRUFBRSxTQUFpQixFQUFFLE9BQWU7Ozs7Ozs7O0lBbE01RCxLQUFLO1FBSGpCLFVBQVUsQ0FBQztZQUNWLFVBQVUsRUFBRSxNQUFNO1NBQ25CLENBQUM7T0FDVyxLQUFLO2dCQW5FbEI7RUFtRTJCLGlCQUFpQjtTQUEvQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIGlzIGEgdGVtcGxhdGUgZm9yIG5ldyBwbHVnaW4gd3JhcHBlcnNcbiAqXG4gKiBUT0RPOlxuICogLSBBZGQvQ2hhbmdlIGluZm9ybWF0aW9uIGJlbG93XG4gKiAtIERvY3VtZW50IHVzYWdlIChpbXBvcnRpbmcsIGV4ZWN1dGluZyBtYWluIGZ1bmN0aW9uYWxpdHkpXG4gKiAtIFJlbW92ZSBhbnkgaW1wb3J0cyB0aGF0IHlvdSBhcmUgbm90IHVzaW5nXG4gKiAtIFJlbW92ZSBhbGwgdGhlIGNvbW1lbnRzIGluY2x1ZGVkIGluIHRoaXMgdGVtcGxhdGUsIEVYQ0VQVCB0aGUgQFBsdWdpbiB3cmFwcGVyIGRvY3MgYW5kIGFueSBvdGhlciBkb2NzIHlvdSBhZGRlZFxuICogLSBSZW1vdmUgdGhpcyBub3RlXG4gKlxuICovXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQbHVnaW4sIENvcmRvdmEsIENvcmRvdmFQcm9wZXJ0eSwgQ29yZG92YUluc3RhbmNlLCBJbnN0YW5jZVByb3BlcnR5LCBJb25pY05hdGl2ZVBsdWdpbiB9IGZyb20gJ0Bpb25pYy1uYXRpdmUvY29yZSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGFnT3B0aW9ucyB7XG4gIHNlcXVlbmNlOiBudW1iZXI7XG4gIHRhZ3M/OiBBcnJheTxzdHJpbmc+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEFsaWFzT3B0aW9ucyB7XG4gIHNlcXVlbmNlOiBudW1iZXI7XG4gIGFsaWFzPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEBuYW1lIGpwdXNoXG4gKiBAZGVzY3JpcHRpb25cbiAqIFRoaXMgcGx1Z2luIGRvZXMgc29tZXRoaW5nXG4gKlxuICogQHVzYWdlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBqcHVzaCB9IGZyb20gJ0Bpb25pYy1uYXRpdmUvanB1c2gnO1xuICpcbiAqXG4gKiBjb25zdHJ1Y3Rvcihwcml2YXRlIGpwdXNoOiBqcHVzaCkgeyB9XG4gKlxuICogLi4uXG4gKlxuICpcbiAqIHRoaXMuanB1c2guZnVuY3Rpb25OYW1lKCdIZWxsbycsIDEyMylcbiAqICAgLnRoZW4oKHJlczogYW55KSA9PiBjb25zb2xlLmxvZyhyZXMpKVxuICogICAuY2F0Y2goKGVycm9yOiBhbnkpID0+IGNvbnNvbGUuZXJyb3IoZXJyb3IpKTtcbiAqXG4gKiBgYGBcbiAqL1xuLy8gQFBsdWdpbih7XG4vLyAgIHBsdWdpbk5hbWU6ICdqcHVzaCcsXG4vLyAgIHBsdWdpbjogJycsIC8vIG5wbSBwYWNrYWdlIG5hbWUsIGV4YW1wbGU6IGNvcmRvdmEtcGx1Z2luLWNhbWVyYVxuLy8gICBwbHVnaW5SZWY6ICcnLCAvLyB0aGUgdmFyaWFibGUgcmVmZXJlbmNlIHRvIGNhbGwgdGhlIHBsdWdpbiwgZXhhbXBsZTogbmF2aWdhdG9yLmdlb2xvY2F0aW9uXG4vLyAgIHJlcG86ICcnLCAvLyB0aGUgZ2l0aHViIHJlcG9zaXRvcnkgVVJMIGZvciB0aGUgcGx1Z2luXG4vLyAgIGluc3RhbGw6ICcnLCAvLyBPUFRJT05BTCBpbnN0YWxsIGNvbW1hbmQsIGluIGNhc2UgdGhlIHBsdWdpbiByZXF1aXJlcyB2YXJpYWJsZXNcbi8vICAgaW5zdGFsbFZhcmlhYmxlczogW10sIC8vIE9QVElPTkFMIHRoZSBwbHVnaW4gcmVxdWlyZXMgdmFyaWFibGVzXG4vLyAgIHBsYXRmb3JtczogW10gLy8gQXJyYXkgb2YgcGxhdGZvcm1zIHN1cHBvcnRlZCwgZXhhbXBsZTogWydBbmRyb2lkJywgJ2lPUyddXG4vLyB9KVxuQFBsdWdpbih7XG4gIHBsdWdpbk5hbWU6ICdKUHVzaCcsXG4gIHBsdWdpbjogJ2pwdXNoLXBob25lZ2FwLXBsdWdpbicsXG4gIHBsdWdpblJlZjogJ3BsdWdpbnMualB1c2hQbHVnaW4nLFxuICByZXBvOiAnaHR0cHM6Ly9naXRodWIuY29tL2pwdXNoL2pwdXNoLXBob25lZ2FwLXBsdWdpbicsXG4gIGluc3RhbGw6ICdpb25pYyBjb3Jkb3ZhIHBsdWdpbiBhZGQganB1c2gtcGhvbmVnYXAtcGx1Z2luIC0tdmFyaWFibGUgQVBQX0tFWT15b3VyX2FwcF9rZXknLFxuICBpbnN0YWxsVmFyaWFibGVzOiBbJ0FQUF9LRVknXSxcbiAgcGxhdGZvcm1zOiBbJ0FuZHJvaWQnLCAnaU9TJ11cbn0pXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBKUHVzaCBleHRlbmRzIElvbmljTmF0aXZlUGx1Z2luIHtcblxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiBkb2VzIHNvbWV0aGluZ1xuICAgKiBAcGFyYW0gYXJnMSB7c3RyaW5nfSBTb21lIHBhcmFtIHRvIGNvbmZpZ3VyZSBzb21ldGhpbmdcbiAgICogQHBhcmFtIGFyZzIge251bWJlcn0gQW5vdGhlciBwYXJhbSB0byBjb25maWd1cmUgc29tZXRoaW5nXG4gICAqIEByZXR1cm4ge1Byb21pc2U8YW55Pn0gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHNvbWV0aGluZyBoYXBwZW5zXG4gICAqL1xuICBAQ29yZG92YSgpXG4gIGZ1bmN0aW9uTmFtZShhcmcxOiBzdHJpbmcsIGFyZzI6IG51bWJlcik6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuOyAvLyBXZSBhZGQgcmV0dXJuOyBoZXJlIHRvIGF2b2lkIGFueSBJREUgLyBDb21waWxlciBlcnJvcnNcbiAgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnLCAnQW5kcm9pZCddXG4gICB9KVxuICBpbml0KCk6IHZvaWQgeyAgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnLCAnQW5kcm9pZCddXG4gICB9KVxuICBzZXREZWJ1Z01vZGUoZW5hYmxlOiBib29sZWFuKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoKVxuICBnZXRSZWdpc3RyYXRpb25JRCgpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHN0b3BQdXNoKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgcmVzdW1lUHVzaCgpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGlzUHVzaFN0b3BwZWQoKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBzZXRUYWdzKHBhcmFtczogVGFnT3B0aW9ucyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgYWRkVGFncyhwYXJhbXM6IFRhZ09wdGlvbnMpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGRlbGV0ZVRhZ3MocGFyYW1zOiBUYWdPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBjbGVhblRhZ3MocGFyYW1zOiBUYWdPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBnZXRBbGxUYWdzKHBhcmFtczogVGFnT3B0aW9ucyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gcGFyYW1zIHsgc2VxdWVuY2U6IG51bWJlciwgdGFnOiBzdHJpbmcgfVxuICAgKi9cbiAgQENvcmRvdmEoKVxuICBjaGVja1RhZ0JpbmRTdGF0ZShwYXJhbXM6IG9iamVjdCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgc2V0QWxpYXMocGFyYW1zOiBBbGlhc09wdGlvbnMpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGRlbGV0ZUFsaWFzKHBhcmFtczogQWxpYXNPcHRpb25zKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBnZXRBbGlhcyhwYXJhbXM6IEFsaWFzT3B0aW9ucyk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmF0ZSB3aGV0aGVyIHRoZSBhcHBsaWNhdGlvbiBub3RpZmljYXRpb24gaGFzIGJlZW4gb3BlbmVkLlxuICAgKiBcbiAgICogaU9TOiAwOiBjbG9zZWQ7ID4xOiBvcGVuZWQuXG4gICAqICBVSVJlbW90ZU5vdGlmaWNhdGlvblR5cGVOb25lID0gMCxcbiAgICogIFVJUmVtb3RlTm90aWZpY2F0aW9uVHlwZUJhZGdlID0gMSA8PCAwLFxuICAgKiAgVUlSZW1vdGVOb3RpZmljYXRpb25UeXBlU291bmQgPSAxIDw8IDEsXG4gICAqICBVSVJlbW90ZU5vdGlmaWNhdGlvblR5cGVBbGVydCA9IDEgPDwgMixcbiAgICogIFVJUmVtb3RlTm90aWZpY2F0aW9uVHlwZU5ld3NzdGFuZENvbnRlbnRBdmFpbGFiaWxpdHkgPSAxIDw8IDNcbiAgICogXG4gICAqIEFuZHJvaWQ6IDA6IGNsb3NlZDsgMTogb3BlbmVkLlxuICAgKi9cbiAgQENvcmRvdmEoKVxuICBnZXRVc2VyTm90aWZpY2F0aW9uU2V0dGluZ3MoKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBjbGVhckxvY2FsTm90aWZpY2F0aW9ucygpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICAvLyBpT1MgQVBJIC0gc3RhcnRcblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIHNldEJhZGdlKGJhZGdlOiBudW1iZXIpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIHJlc2V0QmFkZ2UoKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBzZXRBcHBsaWNhdGlvbkljb25CYWRnZU51bWJlcihiYWRnZTogbnVtYmVyKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoKVxuICBnZXRBcHBsaWNhdGlvbkljb25CYWRnZU51bWJlcigpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIGFkZExvY2FsTm90aWZpY2F0aW9uRm9ySU9TKGRlbGF5VGltZTogbnVtYmVyLCBjb250ZW50OiBzdHJpbmcsIGJhZGdlOiBudW1iZXIsIGlkZW50aWZpZXJLZXk6IHN0cmluZywgZXh0cmFzPzogb2JqZWN0KTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBkZWxldGVMb2NhbE5vdGlmaWNhdGlvbldpdGhJZGVudGlmaWVyS2V5SW5JT1MoaWRlbnRpZmllcktleTogc3RyaW5nKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBhZGREaXNtaXNzQWN0aW9ucyhhY3Rpb25zOiBBcnJheTxvYmplY3Q+LCBjYXRlZ29yeUlkOiBzdHJpbmcpOiB2b2lkIHsgIH1cblxuICBAQ29yZG92YSh7XG4gICAgc3luYzogdHJ1ZSxcbiAgICBwbGF0Zm9ybXM6IFsnaU9TJ11cbiAgIH0pXG4gIGFkZE5vdGlmaWNhdGlvbkFjdGlvbnMoYWN0aW9uczogQXJyYXk8b2JqZWN0PiwgY2F0ZWdvcnlJZDogc3RyaW5nKTogdm9pZCB7ICB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBzZXRMb2NhdGlvbihsYXRpdHVkZTogbnVtYmVyLCBsb25naXR1ZGU6IG51bWJlcik6IHZvaWQgeyAgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgc3RhcnRMb2dQYWdlVmlldyhwYWdlTmFtZTogc3RyaW5nKTogdm9pZCB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKHtcbiAgICBzeW5jOiB0cnVlLFxuICAgIHBsYXRmb3JtczogWydpT1MnXVxuICAgfSlcbiAgc3RvcExvZ1BhZ2VWaWV3KHBhZ2VOYW1lOiBzdHJpbmcpOiB2b2lkIHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoe1xuICAgIHN5bmM6IHRydWUsXG4gICAgcGxhdGZvcm1zOiBbJ2lPUyddXG4gICB9KVxuICBiZWdpbkxvZ1BhZ2VWaWV3KHBhZ2VOYW1lOiBzdHJpbmcsIGR1cmF0aW9uOiBudW1iZXIpOiB2b2lkIHsgcmV0dXJuOyB9XG5cbiAgLy8gaU9TIEFQSSAtIGVuZFxuXG4gIC8vIEFuZHJvaWQgQVBJIC0gc3RhcnRcblxuICBAQ29yZG92YSgpXG4gIGdldENvbm5lY3Rpb25TdGF0ZSgpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldEJhc2ljUHVzaE5vdGlmaWNhdGlvbkJ1aWxkZXIoKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBzZXRDdXN0b21QdXNoTm90aWZpY2F0aW9uQnVpbGRlcigpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIGNsZWFyQWxsTm90aWZpY2F0aW9uKCk6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgY2xlYXJOb3RpZmljYXRpb25CeUlkKGlkOiBudW1iZXIpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldExhdGVzdE5vdGlmaWNhdGlvbk51bShudW06IG51bWJlcik6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIEBDb3Jkb3ZhKClcbiAgYWRkTG9jYWxOb3RpZmljYXRpb24oYnVpbGRlcklkOiBudW1iZXIsIGNvbnRlbnQ6IHN0cmluZywgdGl0bGU6IHN0cmluZywgbm90aWZpY2F0aW9uSWQ6IG51bWJlciwgYnJvYWRjYXN0VGltZTogbnVtYmVyLCBleHRyYXM/OiBzdHJpbmcpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHJlbW92ZUxvY2FsTm90aWZpY2F0aW9uKG5vdGlmaWNhdGlvbklkOiBudW1iZXIpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHJlcG9ydE5vdGlmaWNhdGlvbk9wZW5lZChtc2dJZDogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICByZXF1ZXN0UGVybWlzc2lvbigpOiBQcm9taXNlPGFueT4geyByZXR1cm47IH1cblxuICBAQ29yZG92YSgpXG4gIHNldFNpbGVuY2VUaW1lKHN0YXJ0SG91cjogbnVtYmVyLCBzdGFydE1pbnV0ZTogbnVtYmVyLCBlbmRIb3VyOiBudW1iZXIsIGVuZE1pbnV0ZTogbnVtYmVyKTogUHJvbWlzZTxhbnk+IHsgcmV0dXJuOyB9XG5cbiAgQENvcmRvdmEoKVxuICBzZXRQdXNoVGltZSh3ZWVrZGF5czogQXJyYXk8c3RyaW5nPiwgc3RhcnRIb3VyOiBudW1iZXIsIGVuZEhvdXI6IG51bWJlcik6IFByb21pc2U8YW55PiB7IHJldHVybjsgfVxuXG4gIC8vIEFuZHJvaWQgQVBJIC0gZW5kXG5cbn1cbiJdfQ==
\ No newline at end of file
--- /dev/null
+[{"__symbolic":"module","version":4,"metadata":{"TagOptions":{"__symbolic":"interface"},"AliasOptions":{"__symbolic":"interface"},"JPush":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"@ionic-native/core","name":"IonicNativePlugin","line":67,"character":27},"decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Injectable","line":64,"character":1},"arguments":[{"providedIn":"root"}]}],"members":{"functionName":[{"__symbolic":"method"}],"init":[{"__symbolic":"method"}],"setDebugMode":[{"__symbolic":"method"}],"getRegistrationID":[{"__symbolic":"method"}],"stopPush":[{"__symbolic":"method"}],"resumePush":[{"__symbolic":"method"}],"isPushStopped":[{"__symbolic":"method"}],"setTags":[{"__symbolic":"method"}],"addTags":[{"__symbolic":"method"}],"deleteTags":[{"__symbolic":"method"}],"cleanTags":[{"__symbolic":"method"}],"getAllTags":[{"__symbolic":"method"}],"checkTagBindState":[{"__symbolic":"method"}],"setAlias":[{"__symbolic":"method"}],"deleteAlias":[{"__symbolic":"method"}],"getAlias":[{"__symbolic":"method"}],"getUserNotificationSettings":[{"__symbolic":"method"}],"clearLocalNotifications":[{"__symbolic":"method"}],"setBadge":[{"__symbolic":"method"}],"resetBadge":[{"__symbolic":"method"}],"setApplicationIconBadgeNumber":[{"__symbolic":"method"}],"getApplicationIconBadgeNumber":[{"__symbolic":"method"}],"addLocalNotificationForIOS":[{"__symbolic":"method"}],"deleteLocalNotificationWithIdentifierKeyInIOS":[{"__symbolic":"method"}],"addDismissActions":[{"__symbolic":"method"}],"addNotificationActions":[{"__symbolic":"method"}],"setLocation":[{"__symbolic":"method"}],"startLogPageView":[{"__symbolic":"method"}],"stopLogPageView":[{"__symbolic":"method"}],"beginLogPageView":[{"__symbolic":"method"}],"getConnectionState":[{"__symbolic":"method"}],"setBasicPushNotificationBuilder":[{"__symbolic":"method"}],"setCustomPushNotificationBuilder":[{"__symbolic":"method"}],"clearAllNotification":[{"__symbolic":"method"}],"clearNotificationById":[{"__symbolic":"method"}],"setLatestNotificationNum":[{"__symbolic":"method"}],"addLocalNotification":[{"__symbolic":"method"}],"removeLocalNotification":[{"__symbolic":"method"}],"reportNotificationOpened":[{"__symbolic":"method"}],"requestPermission":[{"__symbolic":"method"}],"setSilenceTime":[{"__symbolic":"method"}],"setPushTime":[{"__symbolic":"method"}]}}}}]
--- /dev/null
+{
+ "name": "@jiguang-ionic/jpush",
+ "version": "2.0.0",
+ "description": "JPush support for ionic-native",
+ "module": "index.js",
+ "typings": "index.d.ts",
+ "author": "hevin",
+ "license": "MIT",
+ "peerDependencies": {
+ "@ionic-native/core": "^5.1.0",
+ "@angular/core": "*",
+ "rxjs": "^6.3.0"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/jpush/jpush-phonegap-plugin"
+ }
+}
--- /dev/null
+The MIT License (MIT)
+
+Copyright (c) JiGuang <support@jpush.cn> (jiguang.cn)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+{
+ "_from": "jpush-phonegap-plugin",
+ "_id": "jpush-phonegap-plugin@3.7.2",
+ "_inBundle": false,
+ "_integrity": "sha512-q5gGu0m1uf6Mf1puFd9o1hp32rok+/GgR39ZDGWdYULc6KX5zy932wdzLDlTYpjBW9Gec/HZmj1HTbQIMvppiA==",
+ "_location": "/jpush-phonegap-plugin",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "tag",
+ "registry": true,
+ "raw": "jpush-phonegap-plugin",
+ "name": "jpush-phonegap-plugin",
+ "escapedName": "jpush-phonegap-plugin",
+ "rawSpec": "",
+ "saveSpec": null,
+ "fetchSpec": "latest"
+ },
+ "_requiredBy": [
+ "#USER",
+ "/"
+ ],
+ "_resolved": "https://registry.npmjs.org/jpush-phonegap-plugin/-/jpush-phonegap-plugin-3.7.2.tgz",
+ "_shasum": "59c085065a0d5d636965f20ed2fdcd30f8a23b2c",
+ "_spec": "jpush-phonegap-plugin",
+ "_where": "/Users/shuwei/works2/cordova/dlapp",
+ "author": {
+ "name": "JiGuang"
+ },
+ "bugs": {
+ "url": "https://github.com/jpush/jpush-phonegap-plugin/issues"
+ },
+ "bundleDependencies": false,
+ "cordova": {
+ "id": "jpush-phonegap-plugin",
+ "platforms": [
+ "ios",
+ "android"
+ ]
+ },
+ "deprecated": false,
+ "description": "JPush for cordova plugin",
+ "devDependencies": {
+ "cordova-plugin-device": "*",
+ "cordova-plugin-jcore": ">=1.3.0"
+ },
+ "homepage": "https://github.com/jpush/jpush-phonegap-plugin#readme",
+ "keywords": [
+ "JPush",
+ "push",
+ "Push",
+ "ecosystem:cordova",
+ "cordova-ios",
+ "cordova-android"
+ ],
+ "license": "MIT",
+ "name": "jpush-phonegap-plugin",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/jpush/jpush-phonegap-plugin.git"
+ },
+ "version": "3.7.2"
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ id="jpush-phonegap-plugin"
+ version="3.7.2">
+
+ <name>JPush</name>
+ <description>JPush for cordova plugin</description>
+ <author>JPush</author>
+ <keywords>JPush,push</keywords>
+ <license>MIT License</license>
+
+ <preference name="APP_KEY" />
+ <preference name="CHANNEL" default="developer-default" />
+
+ <engines>
+ <engine name="cordova" version=">=3.0" />
+ </engines>
+
+ <!-- dependencies -->
+ <dependency id="cordova-plugin-device" />
+ <dependency id="cordova-plugin-jcore" />
+
+ <js-module src="www/JPushPlugin.js" name="JPushPlugin">
+ <clobbers target="JPush" />
+ </js-module>
+
+ <platform name="ios">
+ <config-file target="config.xml" parent="/*">
+ <feature name="JPushPlugin">
+ <param name="ios-package" value="JPushPlugin" />
+ </feature>
+ </config-file>
+ <config-file target="*-Info.plist" parent="UIBackgroundModes">
+ <array>
+ <string>remote-notification</string>
+ </array>
+ </config-file>
+ <config-file target="*-Debug.plist" parent="aps-environment">
+ <string>development</string>
+ </config-file>
+ <config-file target="*-Release.plist" parent="aps-environment">
+ <string>production</string>
+ </config-file>
+ <header-file src="src/ios/Plugins/JPushDefine.h" />
+ <header-file src="src/ios/Plugins/JPushPlugin.h" />
+ <source-file src="src/ios/Plugins/JPushPlugin.m" />
+ <header-file src="src/ios/Plugins/AppDelegate+JPush.h" />
+ <source-file src="src/ios/Plugins/AppDelegate+JPush.m" />
+
+ <header-file src="src/ios/lib/JPUSHService.h" />
+ <source-file src="src/ios/lib/jpush-ios-3.2.1.a" framework="true" />
+ <resource-file src="src/ios/JPushConfig.plist" />
+
+ <framework src="CFNetwork.framework" weak="true" />
+ <framework src="CoreFoundation.framework" weak="true" />
+ <framework src="CoreTelephony.framework" weak="true" />
+ <framework src="SystemConfiguration.framework" weak="true" />
+ <framework src="CoreGraphics.framework" weak="true" />
+ <framework src="Foundation.framework" weak="true" />
+ <framework src="UIKit.framework" weak="true" />
+ <framework src="Security.framework" weak="true" />
+ <framework src="libz.tbd" weak="true" />
+ <framework src="AdSupport.framework" weak="true" />
+ <framework src="UserNotifications.framework" weak="true" />
+ <framework src="libresolv.tbd" weak="true" />
+
+ <config-file target="*JPushConfig.plist" parent="Appkey">
+ <string>$APP_KEY</string>
+ </config-file>
+ </platform>
+
+ <platform name="android">
+ <config-file target="res/xml/config.xml" parent="/*">
+ <feature name="JPushPlugin">
+ <param name="android-package" value="cn.jiguang.cordova.push.JPushPlugin" />
+ </feature>
+ </config-file>
+
+ <config-file target="AndroidManifest.xml" parent="/manifest" mode="merge">
+ <!-- Required 一些系统要求的权限,如访问网络等 -->
+ <permission android:name="$PACKAGE_NAME.permission.JPUSH_MESSAGE"
+ android:protectionLevel="signature" />
+
+ <!-- Required 一些系统要求的权限,如访问网络等-->
+ <uses-permission android:name="$PACKAGE_NAME.permission.JPUSH_MESSAGE" />
+ <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+
+
+
+ <!-- Optional for location -->
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 用于开启 debug 版本的应用在6.0 系统上 层叠窗口权限 -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /><!-- Android Q后台定位权限-->
+ <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.GET_TASKS" />
+ </config-file>
+
+ <config-file target="AndroidManifest.xml" parent="/manifest/application" mode="merge">
+
+
+ <!-- Rich push 核心功能 since 2.0.6-->
+ <activity
+ android:name="cn.jpush.android.ui.PopWinActivity"
+ android:theme="@style/MyDialogStyle"
+ android:exported="false">
+ </activity>
+
+ <!-- Required SDK核心功能-->
+ <activity
+ android:name="cn.jpush.android.ui.PushActivity"
+ android:configChanges="orientation|keyboardHidden"
+ android:theme="@android:style/Theme.NoTitleBar"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="cn.jpush.android.ui.PushActivity" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="$PACKAGE_NAME" />
+ </intent-filter>
+ </activity>
+
+ <!-- Required SDK 核心功能-->
+ <!-- 可配置android:process参数将PushService放在其他进程中 -->
+ <service
+ android:name="cn.jpush.android.service.PushService"
+ android:process=":pushcore"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.REGISTER" />
+ <action android:name="cn.jpush.android.intent.REPORT" />
+ <action android:name="cn.jpush.android.intent.PushService" />
+ <action android:name="cn.jpush.android.intent.PUSH_TIME" />
+ </intent-filter>
+ </service>
+
+ <!-- since 3.0.9 Required SDK 核心功能-->
+ <provider
+ android:authorities="$PACKAGE_NAME.DataProvider"
+ android:name="cn.jpush.android.service.DataProvider"
+ android:process=":pushcore"
+ android:exported="false"
+ />
+
+ <!-- since 1.8.0 option 可选项。用于同一设备中不同应用的JPush服务相互拉起的功能。 -->
+ <!-- 若不启用该功能可删除该组件,将不拉起其他应用也不能被其他应用拉起 -->
+ <service
+ android:name="cn.jpush.android.service.DaemonService"
+ android:enabled="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.DaemonService" />
+ <category android:name="$PACKAGE_NAME" />
+ </intent-filter>
+
+ </service>
+
+ <!-- since 3.1.0 Required SDK 核心功能-->
+ <provider
+ android:authorities="$PACKAGE_NAME.DownloadProvider"
+ android:name="cn.jpush.android.service.DownloadProvider"
+ android:exported="true"
+ />
+
+ <!-- Required SDK核心功能-->
+ <receiver
+ android:name="cn.jpush.android.service.PushReceiver"
+ android:enabled="true"
+ android:exported="false">
+ <intent-filter android:priority="1000">
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED_PROXY" /> <!--Required 显示通知栏 -->
+ <category android:name="$PACKAGE_NAME" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.USER_PRESENT" />
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ </intent-filter>
+ <!-- Optional -->
+ <intent-filter>
+ <action android:name="android.intent.action.PACKAGE_ADDED" />
+ <action android:name="android.intent.action.PACKAGE_REMOVED" />
+
+ <data android:scheme="package" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Required SDK核心功能-->
+ <receiver android:name="cn.jpush.android.service.AlarmReceiver" android:exported="false"/>
+
+ <!--since 3.3.0 接收JPush相关事件-->
+ <receiver android:name="cn.jiguang.cordova.push.JPushEventReceiver">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
+ <category android:name="$PACKAGE_NAME"></category>
+ </intent-filter>
+ </receiver>
+
+ <!--since 3.3.0 Required SDK核心功能-->
+ <activity
+ android:name="cn.jpush.android.service.JNotifyActivity"
+ android:exported="true"
+ android:taskAffinity="jpush.custom"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.JNotifyActivity" />
+ <category android:name="$PACKAGE_NAME" />
+ </intent-filter>
+ </activity>
+
+ <!-- since 3.3.0 Required SDK 核心功能-->
+ <!-- 可配置android:process参数将PushService放在其他进程中 -->
+ <!--User defined. For test only 继承自cn.jpush.android.service.JCommonService-->
+ <service android:name="cn.jiguang.cordova.push.PushService"
+ android:process=":pushcore">
+ <intent-filter>
+ <action android:name="cn.jiguang.user.service.action" />
+ </intent-filter>
+ </service>
+
+
+ <receiver
+ android:name="cn.jiguang.cordova.push.JPushReceiver"
+ android:enabled="true"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="cn.jpush.android.intent.REGISTRATION" />
+ <action android:name="cn.jpush.android.intent.MESSAGE_RECEIVED" />
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_RECEIVED" />
+ <action android:name="cn.jpush.android.intent.NOTIFICATION_OPENED" />
+ <action android:name="cn.jpush.android.intent.CONNECTION" />
+
+ <category android:name="$PACKAGE_NAME" />
+ </intent-filter>
+ </receiver>
+
+ <!-- Required . Enable it you can get statistics data with channel -->
+ <meta-data android:name="JPUSH_CHANNEL" android:value="$CHANNEL"/>
+ <meta-data android:name="JPUSH_APPKEY" android:value="$APP_KEY" /> <!-- </>值来自开发者平台取得的AppKey-->
+
+ </config-file>
+
+ <lib-file src="src/android/libs/jpush-android-3.3.4.jar" />
+
+ <source-file src="src/android/PushService.java" target-dir="src/cn/jiguang/cordova/push" />
+ <source-file src="src/android/JPushPlugin.java" target-dir="src/cn/jiguang/cordova/push" />
+ <source-file src="src/android/JPushReceiver.java" target-dir="src/cn/jiguang/cordova/push" />
+ <source-file src="src/android/JPushEventReceiver.java" target-dir="src/cn/jiguang/cordova/push" />
+
+ <resource-file src="src/android/res/drawable-hdpi/jpush_richpush_btn_selector.xml"
+ target="res/drawable/jpush_richpush_btn_selector.xml" />
+ <resource-file src="src/android/res/drawable-hdpi/jpush_richpush_progressbar.xml"
+ target="res/drawable/jpush_richpush_progressbar.xml" />
+
+ <resource-file src="src/android/res/drawable-hdpi/jpush_ic_richpush_actionbar_back.png"
+ target="res/drawable-hdpi/jpush_ic_richpush_actionbar_back.png" />
+ <resource-file src="src/android/res/drawable-hdpi/jpush_ic_richpush_actionbar_divider.png"
+ target="res/drawable-hdpi/jpush_ic_richpush_actionbar_divider.png" />
+
+ <resource-file src="src/android/res/layout/jpush_popwin_layout.xml"
+ target="res/layout/jpush_popwin_layout.xml" />
+ <resource-file src="src/android/res/layout/jpush_webview_layout.xml"
+ target="res/layout/jpush_webview_layout.xml" />
+ <resource-file src="src/android/res/layout/push_notification.xml"
+ target="res/layout/push_notification.xml" />
+
+ <resource-file src="src/android/res/values/jpush_style.xml"
+ target="res/values/jpush_style.xml" />
+ <resource-file src="src/android/res/values/jpush_string.xml"
+ target="res/values/jpush_string.xml" />
+
+ <resource-file src="src/android/res/values-zh/jpush_string.xml"
+ target="res/values-zh/jpush_string.xml" />
+ </platform>
+</plugin>
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.apache.cordova.CallbackContext;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Map;
+import java.util.Set;
+
+import cn.jpush.android.api.CustomMessage;
+import cn.jpush.android.api.JPushInterface;
+import cn.jpush.android.api.JPushMessage;
+import cn.jpush.android.api.NotificationMessage;
+import cn.jpush.android.service.JPushMessageReceiver;
+
+public class JPushEventReceiver extends JPushMessageReceiver {
+
+ private static final String TAG = JPushEventReceiver.class.getSimpleName();
+
+ @Override
+ public void onTagOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onTagOperatorResult(context, jPushMessage);
+ //Log.e(TAG,"onTagOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) { // success
+ Set<String> tags = jPushMessage.getTags();
+ JSONArray tagsJsonArr = new JSONArray();
+ for (String tag : tags) {
+ tagsJsonArr.put(tag);
+ }
+
+ try {
+ if (tagsJsonArr.length() != 0) {
+ resultJson.put("tags", tagsJsonArr);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onCheckTagOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onCheckTagOperatorResult(context, jPushMessage);
+
+ //Log.e(TAG,"onCheckTagOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) {
+ try {
+ resultJson.put("tag", jPushMessage.getCheckTag());
+ resultJson.put("isBind", jPushMessage.getTagCheckStateResult());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onAliasOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onAliasOperatorResult(context, jPushMessage);
+
+ //Log.e(TAG,"onAliasOperatorResult:"+jPushMessage);
+ JSONObject resultJson = new JSONObject();
+
+ int sequence = jPushMessage.getSequence();
+ try {
+ resultJson.put("sequence", sequence);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ CallbackContext callback = JPushPlugin.eventCallbackMap.get(sequence);
+
+ if (callback == null) {
+ Log.i(TAG, "Unexpected error, callback is null!");
+ return;
+ }
+
+ if (jPushMessage.getErrorCode() == 0) { // success
+ try {
+ if (!TextUtils.isEmpty(jPushMessage.getAlias())) {
+ resultJson.put("alias", jPushMessage.getAlias());
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.success(resultJson);
+
+ } else {
+ try {
+ resultJson.put("code", jPushMessage.getErrorCode());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ callback.error(resultJson);
+ }
+
+ JPushPlugin.eventCallbackMap.remove(sequence);
+ }
+
+ @Override
+ public void onRegister(Context context, String regId) {
+ //Log.e(TAG,"onRegister:"+regId);
+ JPushPlugin.transmitReceiveRegistrationId(regId);
+ }
+
+ @Override
+ public void onMessage(Context context, CustomMessage customMessage) {
+ super.onMessage(context,customMessage);
+ //Log.e(TAG,"onMessage:"+customMessage);
+// String msg = customMessage.message;//intent.getStringExtra(JPushInterface.EXTRA_MESSAGE);
+// Map<String, Object> extras = getNotificationExtras(intent);
+// JPushPlugin.transmitMessageReceive(msg, extras);
+ }
+
+ @Override
+ public void onNotifyMessageArrived(Context context, NotificationMessage notificationMessage) {
+ super.onNotifyMessageArrived(context, notificationMessage);
+
+ //Log.e(TAG,"onNotifyMessageArrived:"+notificationMessage);
+ }
+
+ @Override
+ public void onNotifyMessageOpened(Context context, NotificationMessage notificationMessage) {
+ super.onNotifyMessageOpened(context, notificationMessage);
+ //Log.e(TAG,"onNotifyMessageOpened:"+notificationMessage);
+ }
+
+ @Override
+ public void onMobileNumberOperatorResult(Context context, JPushMessage jPushMessage) {
+ super.onMobileNumberOperatorResult(context, jPushMessage);
+ //Log.e(TAG,"onMobileNumberOperatorResult:"+jPushMessage);
+ }
+
+ @Override
+ public void onMultiActionClicked(Context context, Intent intent) {
+ super.onMultiActionClicked(context, intent);
+ //Log.e(TAG,"onMultiActionClicked:"+intent);
+ }
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import cn.jpush.android.api.BasicPushNotificationBuilder;
+import cn.jpush.android.api.JPushInterface;
+import cn.jpush.android.api.TagAliasCallback;
+import cn.jpush.android.data.JPushLocalNotification;
+
+public class JPushPlugin extends CordovaPlugin {
+
+ private static final String TAG = JPushPlugin.class.getSimpleName();
+
+ private Context mContext;
+
+ private static JPushPlugin instance;
+ private static Activity cordovaActivity;
+
+ static String notificationTitle;
+ static String notificationAlert;
+ static Map<String, Object> notificationExtras = new HashMap<String, Object>();
+
+ static String openNotificationTitle;
+ static String openNotificationAlert;
+ static Map<String, Object> openNotificationExtras = new HashMap<String, Object>();
+
+ static Map<Integer, CallbackContext> eventCallbackMap = new HashMap<Integer, CallbackContext>();
+
+ public JPushPlugin() {
+ instance = this;
+ }
+
+ @Override
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+ super.initialize(cordova, webView);
+ mContext = cordova.getActivity().getApplicationContext();
+
+ JPushInterface.init(mContext);
+
+ cordovaActivity = cordova.getActivity();
+
+ // 如果同时缓存了打开事件 openNotificationAlert 和 消息事件 notificationAlert,只向 UI 发打开事件。
+ // 这样做是为了和 iOS 统一。
+ if (openNotificationAlert != null) {
+ notificationAlert = null;
+ transmitNotificationOpen(openNotificationTitle, openNotificationAlert, openNotificationExtras);
+ }
+ if (notificationAlert != null) {
+ transmitNotificationReceive(notificationTitle, notificationAlert, notificationExtras);
+ }
+ }
+
+ public void onResume(boolean multitasking) {
+ if (openNotificationAlert != null) {
+ notificationAlert = null;
+ transmitNotificationOpen(openNotificationTitle, openNotificationAlert, openNotificationExtras);
+ }
+ if (notificationAlert != null) {
+ transmitNotificationReceive(notificationTitle, notificationAlert, notificationExtras);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ cordovaActivity = null;
+ instance = null;
+ }
+
+ private static JSONObject getMessageObject(String message, Map<String, Object> extras) {
+ JSONObject data = new JSONObject();
+ try {
+ data.put("message", message);
+ JSONObject jExtras = new JSONObject();
+ for (Entry<String, Object> entry : extras.entrySet()) {
+ if (entry.getKey().equals("cn.jpush.android.EXTRA")) {
+ JSONObject jo;
+ if (TextUtils.isEmpty((String) entry.getValue())) {
+ jo = new JSONObject();
+ } else {
+ jo = new JSONObject((String) entry.getValue());
+ String key;
+ Iterator keys = jo.keys();
+ while (keys.hasNext()) {
+ key = keys.next().toString();
+ jExtras.put(key, jo.getString(key));
+ }
+ }
+ jExtras.put("cn.jpush.android.EXTRA", jo);
+ } else {
+ jExtras.put(entry.getKey(), entry.getValue());
+ }
+ }
+ if (jExtras.length() > 0) {
+ data.put("extras", jExtras);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ private static JSONObject getNotificationObject(String title, String alert, Map<String, Object> extras) {
+ JSONObject data = new JSONObject();
+ try {
+ data.put("title", title);
+ data.put("alert", alert);
+ JSONObject jExtras = new JSONObject();
+ for (Entry<String, Object> entry : extras.entrySet()) {
+ if (entry.getKey().equals("cn.jpush.android.EXTRA")) {
+ JSONObject jo;
+ if (TextUtils.isEmpty((String) entry.getValue())) {
+ jo = new JSONObject();
+ } else {
+ jo = new JSONObject((String) entry.getValue());
+ String key;
+ Iterator keys = jo.keys();
+ while (keys.hasNext()) {
+ key = keys.next().toString();
+ jExtras.put(key, jo.getString(key));
+ }
+ }
+ jExtras.put("cn.jpush.android.EXTRA", jo);
+ } else {
+ jExtras.put(entry.getKey(), entry.getValue());
+ }
+ }
+ if (jExtras.length() > 0) {
+ data.put("extras", jExtras);
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ static void transmitMessageReceive(String message, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getMessageObject(message, extras);
+ String format = "window.plugins.jPushPlugin.receiveMessageInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ }
+
+ static void transmitNotificationOpen(String title, String alert, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getNotificationObject(title, alert, extras);
+ String format = "window.plugins.jPushPlugin.openNotificationInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ JPushPlugin.openNotificationTitle = null;
+ JPushPlugin.openNotificationAlert = null;
+ }
+
+ static void transmitNotificationReceive(String title, String alert, Map<String, Object> extras) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = getNotificationObject(title, alert, extras);
+ String format = "window.plugins.jPushPlugin.receiveNotificationInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ JPushPlugin.notificationTitle = null;
+ JPushPlugin.notificationAlert = null;
+ }
+
+ static void transmitReceiveRegistrationId(String rId) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = new JSONObject();
+ try {
+ data.put("registrationId", rId);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ String format = "window.plugins.jPushPlugin.receiveRegistrationIdInAndroidCallback(%s);";
+ final String js = String.format(format, data.toString());
+ cordovaActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + js);
+ }
+ });
+ }
+
+ @Override
+ public boolean execute(final String action, final JSONArray data, final CallbackContext callbackContext)
+ throws JSONException {
+ cordova.getThreadPool().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Method method = JPushPlugin.class.getDeclaredMethod(action, JSONArray.class, CallbackContext.class);
+ method.invoke(JPushPlugin.this, data, callbackContext);
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+ });
+ return true;
+ }
+
+ void init(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.init(mContext);
+ }
+
+ void setDebugMode(JSONArray data, CallbackContext callbackContext) {
+ boolean mode;
+ try {
+ mode = data.getBoolean(0);
+ JPushInterface.setDebugMode(mode);
+ callbackContext.success();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ void stopPush(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.stopPush(mContext);
+ callbackContext.success();
+ }
+
+ void resumePush(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.resumePush(mContext);
+ callbackContext.success();
+ }
+
+ void isPushStopped(JSONArray data, CallbackContext callbackContext) {
+ boolean isStopped = JPushInterface.isPushStopped(mContext);
+ if (isStopped) {
+ callbackContext.success(1);
+ } else {
+ callbackContext.success(0);
+ }
+ }
+
+ void areNotificationEnabled(JSONArray data, final CallbackContext callback) {
+ int isEnabled;
+ if (hasPermission("OP_POST_NOTIFICATION")) {
+ isEnabled = 1;
+ } else {
+ isEnabled = 0;
+ }
+ callback.success(isEnabled);
+ }
+
+ void setLatestNotificationNum(JSONArray data, CallbackContext callbackContext) {
+ int num = -1;
+ try {
+ num = data.getInt(0);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading num json");
+ }
+ if (num != -1) {
+ JPushInterface.setLatestNotificationNumber(mContext, num);
+ } else {
+ callbackContext.error("error num");
+ }
+ }
+
+ void setPushTime(JSONArray data, CallbackContext callbackContext) {
+ Set<Integer> days = new HashSet<Integer>();
+ JSONArray dayArray;
+ int startHour = -1;
+ int endHour = -1;
+ try {
+ dayArray = data.getJSONArray(0);
+ for (int i = 0; i < dayArray.length(); i++) {
+ days.add(dayArray.getInt(i));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading days json");
+ }
+ try {
+ startHour = data.getInt(1);
+ endHour = data.getInt(2);
+ } catch (JSONException e) {
+ callbackContext.error("error reading hour json");
+ }
+ Context context = mContext;
+ JPushInterface.setPushTime(context, days, startHour, endHour);
+ callbackContext.success();
+ }
+
+ void getRegistrationID(JSONArray data, CallbackContext callbackContext) {
+ Context context = mContext;
+ String regID = JPushInterface.getRegistrationID(context);
+ callbackContext.success(regID);
+ }
+
+ void onResume(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.onResume(this.cordova.getActivity());
+ }
+
+ void onPause(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.onPause(this.cordova.getActivity());
+ }
+
+ void reportNotificationOpened(JSONArray data, CallbackContext callbackContext) {
+ try {
+ String msgID;
+ msgID = data.getString(0);
+ JPushInterface.reportNotificationOpened(this.cordova.getActivity(), msgID);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ void setAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ String alias = null;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ alias = params.getString("alias");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.setAlias(mContext, sequence, alias);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void deleteAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.deleteAlias(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getAlias(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.getAlias(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void setTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.setTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void addTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.addTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void deleteTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ Set<String> tags = new HashSet<String>();
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ JSONArray tagsArr = params.getJSONArray("tags");
+ for (int i = 0; i < tagsArr.length(); i++) {
+ tags.add(tagsArr.getString(i));
+ }
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.deleteTags(mContext, sequence, tags);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void cleanTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.cleanTags(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getAllTags(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.getAllTags(mContext, sequence);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void checkTagBindState(JSONArray data, CallbackContext callbackContext) {
+ int sequence = -1;
+ String tag = null;
+
+ try {
+ JSONObject params = data.getJSONObject(0);
+ sequence = params.getInt("sequence");
+ tag = params.getString("tag");
+
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("Parameters error.");
+ }
+
+ JPushInterface.checkTagBindState(mContext, sequence, tag);
+ eventCallbackMap.put(sequence, callbackContext);
+ }
+
+ void getConnectionState(JSONArray data, CallbackContext callback) {
+ boolean isConnected = JPushInterface.getConnectionState(cordovaActivity.getApplicationContext());
+ if (isConnected) {
+ callback.success(1);
+ } else {
+ callback.success(0);
+ }
+ }
+
+ /**
+ * 自定义通知行为,声音、震动、呼吸灯等。
+ */
+ void setBasicPushNotificationBuilder(JSONArray data, CallbackContext callbackContext) {
+ BasicPushNotificationBuilder builder = new BasicPushNotificationBuilder(this.cordova.getActivity());
+ builder.developerArg0 = "Basic builder 1";
+ JPushInterface.setPushNotificationBuilder(1, builder);
+ JSONObject obj = new JSONObject();
+ try {
+ obj.put("id", 1);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 自定义推送通知栏样式,需要自己实现具体代码。 http://docs.jiguang.cn/client/android_tutorials/#_11
+ */
+ void setCustomPushNotificationBuilder(JSONArray data, CallbackContext callbackContext) {
+ // CustomPushNotificationBuilder builder = new CustomPushNotificationBuilder(
+ // this.cordova.getActivity(), R.layout.test_notification_layout,
+ // R.id.icon, R.id.title, R.id.text);
+ // JPushInterface.setPushNotificationBuilder(2, builder);
+ // JPushInterface.setDefaultPushNotificationBuilder(builder);
+ }
+
+ void clearAllNotification(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.clearAllNotifications(this.cordova.getActivity());
+ }
+
+ void clearNotificationById(JSONArray data, CallbackContext callbackContext) {
+ int notificationId = -1;
+ try {
+ notificationId = data.getInt(0);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error reading id json");
+ return;
+ }
+ if (notificationId != -1) {
+ JPushInterface.clearNotificationById(this.cordova.getActivity(), notificationId);
+ } else {
+ callbackContext.error("error id");
+ }
+ }
+
+ void addLocalNotification(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int builderId = data.getInt(0);
+ String content = data.getString(1);
+ String title = data.getString(2);
+ int notificationID = data.getInt(3);
+ int broadcastTime = data.getInt(4);
+ String extrasStr = data.isNull(5) ? "" : data.getString(5);
+ JSONObject extras = new JSONObject();
+ if (!extrasStr.isEmpty()) {
+ extras = new JSONObject(extrasStr);
+ }
+
+ JPushLocalNotification ln = new JPushLocalNotification();
+ ln.setBuilderId(builderId);
+ ln.setContent(content);
+ ln.setTitle(title);
+ ln.setNotificationId(notificationID);
+ ln.setBroadcastTime(System.currentTimeMillis() + broadcastTime);
+ ln.setExtras(extras.toString());
+
+ JPushInterface.addLocalNotification(this.cordova.getActivity(), ln);
+ }
+
+ void removeLocalNotification(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int notificationID = data.getInt(0);
+ JPushInterface.removeLocalNotification(this.cordova.getActivity(), notificationID);
+ }
+
+ void clearLocalNotifications(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.clearLocalNotifications(this.cordova.getActivity());
+ }
+
+ /**
+ * 设置通知静默时间 http://docs.jpush.io/client/android_api/#api_5
+ */
+ void setSilenceTime(JSONArray data, CallbackContext callbackContext) {
+ try {
+ int startHour = data.getInt(0);
+ int startMinute = data.getInt(1);
+ int endHour = data.getInt(2);
+ int endMinute = data.getInt(3);
+ if (!isValidHour(startHour) || !isValidMinute(startMinute)) {
+ callbackContext.error("开始时间数值错误");
+ return;
+ }
+ if (!isValidHour(endHour) || !isValidMinute(endMinute)) {
+ callbackContext.error("结束时间数值错误");
+ return;
+ }
+ JPushInterface.setSilenceTime(this.cordova.getActivity(), startHour, startMinute, endHour, endMinute);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ callbackContext.error("error: reading json data.");
+ }
+ }
+
+ void setGeofenceInterval(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ long interval = data.getLong(0);
+ JPushInterface.setGeofenceInterval(this.cordova.getActivity(), interval);
+ }
+
+ void setMaxGeofenceNumber(JSONArray data, CallbackContext callbackContext) throws JSONException {
+ int maxNumber = data.getInt(0);
+ JPushInterface.setMaxGeofenceNumber(mContext, maxNumber);
+ }
+
+ private boolean isValidHour(int hour) {
+ return !(hour < 0 || hour > 23);
+ }
+
+ private boolean isValidMinute(int minute) {
+ return !(minute < 0 || minute > 59);
+ }
+
+ /**
+ * 用于 Android 6.0 以上系统申请权限,具体可参考:
+ * http://docs.Push.io/client/android_api/#android-60
+ */
+ void requestPermission(JSONArray data, CallbackContext callbackContext) {
+ JPushInterface.requestPermission(this.cordova.getActivity());
+ }
+
+ private final TagAliasCallback mTagWithAliasCallback = new TagAliasCallback() {
+ @Override
+ public void gotResult(int code, String alias, Set<String> tags) {
+ if (instance == null) {
+ return;
+ }
+ JSONObject data = new JSONObject();
+ try {
+ data.put("resultCode", code);
+ data.put("tags", tags);
+ data.put("alias", alias);
+ final String jsEvent = String.format("cordova.fireDocumentEvent('jpush.setTagsWithAlias',%s)",
+ data.toString());
+ cordova.getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ instance.webView.loadUrl("javascript:" + jsEvent);
+ }
+ });
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
+ private boolean hasPermission(String appOpsServiceId) {
+
+ Context context = cordova.getActivity().getApplicationContext();
+ if (Build.VERSION.SDK_INT >= 24) {
+ NotificationManager mNotificationManager = (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ return mNotificationManager.areNotificationsEnabled();
+ } else {
+ AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ ApplicationInfo appInfo = context.getApplicationInfo();
+
+ String pkg = context.getPackageName();
+ int uid = appInfo.uid;
+ Class appOpsClazz;
+
+ try {
+ appOpsClazz = Class.forName(AppOpsManager.class.getName());
+ Method checkOpNoThrowMethod = appOpsClazz.getMethod("checkOpNoThrow", Integer.TYPE, Integer.TYPE,
+ String.class);
+ Field opValue = appOpsClazz.getDeclaredField(appOpsServiceId);
+ int value = opValue.getInt(Integer.class);
+ Object result = checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg);
+ return Integer.parseInt(result.toString()) == AppOpsManager.MODE_ALLOWED;
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return false;
+ }
+
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import cn.jpush.android.api.JPushInterface;
+
+public class JPushReceiver extends BroadcastReceiver {
+
+ private static final List<String> IGNORED_EXTRAS_KEYS = Arrays.asList("cn.jpush.android.TITLE",
+ "cn.jpush.android.MESSAGE", "cn.jpush.android.APPKEY", "cn.jpush.android.NOTIFICATION_CONTENT_TITLE","key_show_entity","platform");
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(JPushInterface.ACTION_REGISTRATION_ID)) {
+ String rId = intent.getStringExtra(JPushInterface.EXTRA_REGISTRATION_ID);
+ JPushPlugin.transmitReceiveRegistrationId(rId);
+ } else if (action.equals(JPushInterface.ACTION_MESSAGE_RECEIVED)) {
+ handlingMessageReceive(intent);
+ } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_RECEIVED)) {
+ handlingNotificationReceive(context, intent);
+ } else if (action.equals(JPushInterface.ACTION_NOTIFICATION_OPENED)) {
+ handlingNotificationOpen(context, intent);
+ }
+ }
+
+ private void handlingMessageReceive(Intent intent) {
+ String msg = intent.getStringExtra(JPushInterface.EXTRA_MESSAGE);
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.transmitMessageReceive(msg, extras);
+ }
+
+ private void handlingNotificationOpen(Context context, Intent intent) {
+ String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE);
+ JPushPlugin.openNotificationTitle = title;
+
+ String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT);
+ JPushPlugin.openNotificationAlert = alert;
+
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.openNotificationExtras = extras;
+
+ JPushPlugin.transmitNotificationOpen(title, alert, extras);
+
+ Intent launch = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
+ if (launch != null) {
+ launch.addCategory(Intent.CATEGORY_LAUNCHER);
+ launch.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ context.startActivity(launch);
+ }
+ }
+
+ private void handlingNotificationReceive(Context context, Intent intent) {
+ String title = intent.getStringExtra(JPushInterface.EXTRA_NOTIFICATION_TITLE);
+ JPushPlugin.notificationTitle = title;
+
+ String alert = intent.getStringExtra(JPushInterface.EXTRA_ALERT);
+ JPushPlugin.notificationAlert = alert;
+
+ Map<String, Object> extras = getNotificationExtras(intent);
+ JPushPlugin.notificationExtras = extras;
+
+ JPushPlugin.transmitNotificationReceive(title, alert, extras);
+ }
+
+ private Map<String, Object> getNotificationExtras(Intent intent) {
+ Map<String, Object> extrasMap = new HashMap<String, Object>();
+ for (String key : intent.getExtras().keySet()) {
+ if (!IGNORED_EXTRAS_KEYS.contains(key)) {
+ if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
+ extrasMap.put(key, intent.getIntExtra(key, 0));
+ } else {
+ extrasMap.put(key, intent.getStringExtra(key));
+ }
+ }
+ }
+ return extrasMap;
+ }
+}
--- /dev/null
+package cn.jiguang.cordova.push;
+
+import cn.jpush.android.service.JCommonService;
+
+public class PushService extends JCommonService {
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- 获得焦点但未按下时的背景图片 -->
+ <item
+ android:state_focused="true"
+ android:state_enabled="true"
+ android:state_pressed="false"
+ android:drawable="@drawable/jpush_ic_richpush_actionbar_back" />
+ <!-- 按下时的背景图片 -->
+ <item
+ android:state_enabled="true"
+ android:state_pressed="true"
+ android:drawable="@android:color/darker_gray" />
+ <!-- 按下时的背景图片 -->
+ <item
+ android:state_enabled="true"
+ android:state_checked="true"
+ android:drawable="@android:color/darker_gray" />
+ <!-- 默认时的背景图片 -->
+ <item android:drawable="@drawable/jpush_ic_richpush_actionbar_back" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <!-- 背景 gradient是渐变,corners定义的是圆角 -->
+ <item android:id="@android:id/background">
+ <shape>
+ <solid android:color="#ffffff" />
+ </shape>
+ </item>
+
+ <!-- 进度条 -->
+ <item android:id="@android:id/progress">
+ <clip>
+ <shape>
+ <solid android:color="#4393ea" />
+ </shape>
+ </clip>
+ </item>
+
+</layer-list>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/popLayoutId"
+ style="@style/MyDialogStyle"
+ android:orientation="vertical"
+ android:layout_width="280dp"
+ android:layout_height="250dp" >
+
+ <WebView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/wvPopwin"/>
+
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<cn.jpush.android.ui.FullScreenView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/actionbarLayoutId"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <RelativeLayout
+ android:id="@+id/rlRichpushTitleBar"
+ android:layout_width="match_parent"
+ android:layout_height="40.0dp"
+ android:background="#29313a">
+
+ <ImageButton
+ android:id="@+id/imgRichpushBtnBack"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="9dp"
+ android:layout_marginRight="10dp"
+ android:background="@drawable/jpush_richpush_btn_selector" />
+
+ <ImageView
+ android:id="@+id/imgView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_toRightOf="@id/imgRichpushBtnBack"
+ android:clickable="false"
+ android:src="@drawable/jpush_ic_richpush_actionbar_divider" />
+
+ <TextView
+ android:id="@+id/tvRichpushTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="7dp"
+ android:layout_marginRight="5dp"
+ android:layout_toRightOf="@id/imgView"
+ android:clickable="false"
+ android:text=" "
+ android:textSize="20sp"
+ android:textColor="#ffffff" />
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@+id/pushPrograssBar"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:progress="0"
+ android:progressDrawable="@drawable/jpush_richpush_progressbar"
+ style="?android:attr/progressBarStyleHorizontal" />
+ <WebView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/fullWebView"
+ android:background="#000000" />
+
+</cn.jpush.android.ui.FullScreenView>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ android:id="@+id/push_root_view"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="4dp"
+ android:paddingTop="2dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ >
+
+ <ImageView
+ android:id="@+id/push_notification_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"/>
+ <RelativeLayout
+ android:id="@+id/push_notification_style_default"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:id="@+id/push_notification_layout_lefttop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/push_notification_small_icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginLeft="6dp"
+ android:scaleType="centerInside"/>
+ <TextView
+ android:id="@+id/push_notification_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:maxLines="1"
+ android:maxWidth="200dp"
+ android:maxLength="24"
+ android:textColor="@android:color/black"
+ android:textSize="12sp"/>
+ <TextView
+ android:id="@+id/push_notification_dot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:text="· "
+ android:textColor="@android:color/black"
+ android:textSize="20sp"/>
+ <TextView
+ android:maxLines="1"
+ android:id="@+id/push_notification_date"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:textSize="12sp"
+ />
+ </LinearLayout>
+
+
+ <ImageView
+ android:id="@+id/push_notification_big_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentRight="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:scaleType="centerInside"/>
+
+ <TextView
+ android:id="@+id/push_notification_sub_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_layout_lefttop"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:visibility="gone"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="1"
+ />
+
+ <TextView
+ android:id="@+id/push_notification_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_sub_title"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="2"
+ android:ellipsize="end"
+ />
+ <TextView
+ android:id="@+id/push_notification_content_one_line"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:textColor="@android:color/black"
+ android:layout_below="@id/push_notification_sub_title"
+ android:layout_toLeftOf="@+id/push_notification_big_icon"
+ android:layout_marginLeft="6dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="1"
+ android:ellipsize="end"
+ />
+ </RelativeLayout>
+ <RelativeLayout
+ android:id="@+id/push_notification_style_1"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@+id/push_notification_style_1_big_icon"
+ android:layout_width="50dp"
+ android:layout_height="50dp"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:scaleType="centerInside"/>
+ <LinearLayout
+ android:layout_marginLeft="6dp"
+ android:layout_toRightOf="@+id/push_notification_style_1_big_icon"
+ android:orientation="vertical"
+ android:layout_centerVertical="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/push_notification_style_1_date"
+ android:textSize="12sp"
+ android:layout_alignParentRight="true"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ <TextView
+ android:id="@+id/push_notification_style_1_title"
+ android:layout_alignParentLeft="true"
+ android:layout_toLeftOf="@+id/push_notification_style_1_date"
+ android:textSize="12sp"
+ android:textStyle="bold"
+ android:maxLines="1"
+ android:layout_marginRight="8dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </RelativeLayout>
+ <TextView
+ android:id="@+id/push_notification_style_1_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/black"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="1dp"
+ android:textSize="13sp"
+ android:maxLines="2"
+ android:ellipsize="end" />
+ </LinearLayout>
+ </RelativeLayout>
+
+</RelativeLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="jg_channel_name_p_min">不重要</string>
+ <string name="jg_channel_name_p_low">不重要</string>
+ <string name="jg_channel_name_p_default">普通</string>
+ <string name="jg_channel_name_p_high">重要</string>
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="jg_channel_name_p_min">LOW</string>
+ <string name="jg_channel_name_p_low">LOW</string>
+ <string name="jg_channel_name_p_default">NORMAL</string>
+ <string name="jg_channel_name_p_high">HIGH</string>
+
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style name="MyDialogStyle">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowFrame">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+ <item name="android:backgroundDimEnabled">true</item>
+ </style>
+</resources>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Appkey</key>
+ <string></string>
+ <key>Channel</key>
+ <string>channel name</string>
+ <key>IsProduction</key>
+ <false/>
+ <key>IsIDFA</key>
+ <false/>
+ <key>Delay</key>
+ <false/>
+</dict>
+</plist>
--- /dev/null
+//\r
+// AppDelegate+JPush.h\r
+// delegateExtention\r
+//\r
+// Created by 张庆贺 on 15/8/3.\r
+// Copyright (c) 2015年 JPush. All rights reserved.\r
+//\r
+\r
+#import "AppDelegate.h"\r
+#import <UserNotifications/UserNotifications.h>\r
+#import "JPUSHService.h"\r
+\r
+@interface AppDelegate (JPush) <JPUSHRegisterDelegate>\r
+-(void)registerForRemoteNotification;\r
+-(void)startJPushSDK;\r
+@end\r
--- /dev/null
+//
+// AppDelegate+JPush.m
+// delegateExtention
+//
+// Created by 张庆贺 on 15/8/3.
+// Copyright (c) 2015年 JPush. All rights reserved.
+//
+
+#import "AppDelegate+JPush.h"
+#import "JPushPlugin.h"
+#import <objc/runtime.h>
+#import <AdSupport/AdSupport.h>
+#import <UserNotifications/UserNotifications.h>
+#import "JPushDefine.h"
+
+@implementation AppDelegate (JPush)
+
++(void)load{
+ Method origin1;
+ Method swizzle1;
+ origin1 = class_getInstanceMethod([self class],@selector(init));
+ swizzle1 = class_getInstanceMethod([self class], @selector(init_plus));
+ method_exchangeImplementations(origin1, swizzle1);
+}
+
+-(instancetype)init_plus{
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidLaunch:) name:UIApplicationDidFinishLaunchingNotification object:nil];
+ return [self init_plus];
+}
+
+NSDictionary *_launchOptions;
+-(void)applicationDidLaunch:(NSNotification *)notification{
+
+ if (!_jpushEventCache) {
+ _jpushEventCache = @{}.mutableCopy;
+ }
+
+ [JPUSHService registrationIDCompletionHandler:^(int resCode, NSString *registrationID) {
+ NSDictionary *event = @{@"registrationId": registrationID?:@""};
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_receiveRegistrationId jsString:[event toJsonString]];
+ }];
+
+ if (notification != nil &&
+ [[UIDevice currentDevice].systemVersion floatValue] < 10.0) {// iOS 10 以后通过 openNotification 这个回调触发事件。
+ if (notification.userInfo) {
+
+ if ([notification.userInfo valueForKey:UIApplicationLaunchOptionsRemoteNotificationKey]) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification
+ jsString:[[self jpushFormatAPNSDic: notification.userInfo[UIApplicationLaunchOptionsRemoteNotificationKey]] toJsonString]];
+ }
+
+ if ([notification.userInfo valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]) {
+ UILocalNotification *localNotification = [notification.userInfo valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
+ NSMutableDictionary *localNotificationEvent = @{}.mutableCopy;
+ localNotificationEvent[@"content"] = localNotification.alertBody;
+ localNotificationEvent[@"badge"] = @(localNotification.applicationIconBadgeNumber);
+ localNotificationEvent[@"extras"] = localNotification.userInfo;
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification jsString:[localNotificationEvent toJsonString]];
+ }
+ }
+ }
+
+ [JPUSHService setDebugMode];
+
+ NSString *plistPath = [[NSBundle mainBundle] pathForResource:JPushConfig_FileName ofType:@"plist"];
+ NSMutableDictionary *plistData = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+ NSNumber *delay = [plistData valueForKey:JPushConfig_Delay];
+
+ _launchOptions = notification.userInfo;
+
+ if (![delay boolValue]) {
+ [self startJPushSDK];
+ }
+}
+
+-(void)startJPushSDK{
+ [self registerForRemoteNotification];
+ [JPushPlugin setupJPushSDK:_launchOptions];
+}
+
+- (void)jpushSDKDidLoginNotification {
+ NSDictionary *event = @{@"registrationId": JPUSHService.registrationID};
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_receiveRegistrationId jsString:[event toJsonString]];
+}
+
+- (NSMutableDictionary *)jpushFormatAPNSDic:(NSDictionary *)dic {
+ NSMutableDictionary *extras = @{}.mutableCopy;
+ for (NSString *key in dic) {
+ if([key isEqualToString:@"_j_business"] ||
+ [key isEqualToString:@"_j_msgid"] ||
+ [key isEqualToString:@"_j_uid"] ||
+ [key isEqualToString:@"actionIdentifier"] ||
+ [key isEqualToString:@"aps"]) {
+ continue;
+ }
+ extras[key] = dic[key];
+ }
+ NSMutableDictionary *formatDic = dic.mutableCopy;
+ formatDic[@"extras"] = extras;
+ return formatDic;
+}
+
+-(void)registerForRemoteNotification{
+ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
+#ifdef NSFoundationVersionNumber_iOS_9_x_Max
+ JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
+ entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
+ [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
+#endif
+ }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
+ //可以添加自定义categories
+ [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
+ UIUserNotificationTypeSound |
+ UIUserNotificationTypeAlert)
+ categories:nil];
+ } else if([[UIDevice currentDevice].systemVersion floatValue] < 8.0){
+ //categories 必须为nil
+ [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
+ UIRemoteNotificationTypeSound |
+ UIRemoteNotificationTypeAlert)
+ categories:nil];
+ }
+}
+
+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+ [JPUSHService registerDeviceToken:deviceToken];
+}
+
+-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
+ [JPUSHService handleRemoteNotification:userInfo];
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveNotification jsString:[userInfo toJsonString]];
+}
+
+-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
+ [JPUSHService handleRemoteNotification:userInfo];
+ NSString *eventName;
+ switch ([UIApplication sharedApplication].applicationState) {
+ case UIApplicationStateBackground:
+ eventName = JPushDocumentEvent_BackgroundNotification;
+ break;
+ default:
+ eventName = JPushDocumentEvent_ReceiveNotification;
+ break;
+ }
+
+ [JPushPlugin fireDocumentEvent:eventName jsString:[[self jpushFormatAPNSDic:userInfo] toJsonString]];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completionHandler(UIBackgroundFetchResultNewData);
+ });
+}
+
+-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler{
+ NSMutableDictionary *userInfo = @{}.mutableCopy;
+
+ if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
+ userInfo = [self jpushFormatAPNSDic:notification.request.content.userInfo];
+ } else {
+ UNNotificationContent *content = notification.request.content;
+ userInfo[@"content"] = content.body;
+ userInfo[@"badge"] = content.badge;
+ userInfo[@"extras"] = content.userInfo;
+ userInfo[@"identifier"] = notification.request.identifier;
+ }
+
+ completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
+
+ if ([userInfo[@"aps"][@"content-available"] isEqualToNumber:@(1)]) {// content-available 当用户开启后台推送是,防止触发两次事件
+ return;
+ }
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveNotification jsString:[userInfo toJsonString]];
+
+}
+
+-(void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler{
+ UNNotification *notification = response.notification;
+ NSMutableDictionary *userInfo = @{}.mutableCopy;
+
+ if ([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
+ userInfo = [self jpushFormatAPNSDic:notification.request.content.userInfo];
+ } else {
+ UNNotificationContent *content = notification.request.content;
+ userInfo[@"content"] = content.body;
+ userInfo[@"badge"] = content.badge;
+ userInfo[@"extras"] = content.userInfo;
+ userInfo[@"identifier"] = notification.request.identifier;
+ }
+
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_OpenNotification jsString:[userInfo toJsonString]];
+ completionHandler();
+}
+
+- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
+ NSMutableDictionary *localNotificationEvent = @{}.mutableCopy;
+ localNotificationEvent[@"content"] = notification.alertBody;
+ localNotificationEvent[@"badge"] = @(notification.applicationIconBadgeNumber);
+ localNotificationEvent[@"extras"] = notification.userInfo;
+
+ [[NSNotificationCenter defaultCenter] postNotificationName:JPushDocumentEvent_ReceiveLocalNotification object:localNotificationEvent];
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ // [application setApplicationIconBadgeNumber:0];
+ // [application cancelAllLocalNotifications];
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ // [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
+}
+
+@end
--- /dev/null
+//
+// ConstantDef.h
+// jmessage
+//
+// Created by ljg on 16/1/19.
+//
+//
+
+#ifndef ConstantDef_h
+#define ConstantDef_h
+
+
+
+#endif /* ConstantDef_h */
+
+#define WEAK_SELF(weakSelf) __weak __typeof(&*self)weakSelf = self;
+
+static NSString *const JPushConfig_FileName = @"JPushConfig";
+static NSString *const JPushConfig_Appkey = @"Appkey";
+static NSString *const JPushConfig_Channel = @"Channel";
+static NSString *const JPushConfig_IsProduction = @"IsProduction";
+static NSString *const JPushConfig_IsIDFA = @"IsIDFA";
+static NSString *const JPushConfig_Delay = @"Delay";
+
+static NSString *const JPushDocumentEvent_ReceiveNotification = @"receiveNotification";
+static NSString *const JPushDocumentEvent_OpenNotification = @"openNotification";
+static NSString *const JPushDocumentEvent_BackgroundNotification = @"backgroundNotification";
+static NSString *const JPushDocumentEvent_SetTagsWithAlias = @"setTagsWithAlias";
+static NSString *const JPushDocumentEvent_ReceiveMessage = @"receiveMessage";
+static NSString *const JPushDocumentEvent_ReceiveLocalNotification = @"receiveLocalNotification";
+
+static NSString *const JPushDocumentEvent_receiveRegistrationId = @"receiveRegistrationId";
--- /dev/null
+//
+// PushTalkPlugin.h
+// PushTalk
+//
+// Created by zhangqinghe on 13-12-13.
+//
+//
+
+#import <Cordova/CDV.h>
+
+static NSMutableDictionary *_jpushEventCache;
+
+@interface JPushPlugin : CDVPlugin{
+
+}
+
+//注册通知服务并启动 SDK
+-(void)startJPushSDK:(CDVInvokedUrlCommand*)command;
+
+//以下为js中可调用接口
+//设置标签、别名
+-(void)setTags:(CDVInvokedUrlCommand*)command;
+-(void)addTags:(CDVInvokedUrlCommand*)command;
+-(void)deleteTags:(CDVInvokedUrlCommand*)command;
+-(void)cleanTags:(CDVInvokedUrlCommand*)command;
+-(void)getAllTags:(CDVInvokedUrlCommand*)command;
+-(void)checkTagBindState:(CDVInvokedUrlCommand*)command;
+
+-(void)setAlias:(CDVInvokedUrlCommand*)command;
+-(void)deleteAlias:(CDVInvokedUrlCommand*)command;
+-(void)getAlias:(CDVInvokedUrlCommand*)command;
+
+//获取 RegistrationID
+-(void)getRegistrationID:(CDVInvokedUrlCommand*)command;
+
+//页面统计
+-(void)startLogPageView:(CDVInvokedUrlCommand*)command;
+-(void)stopLogPageView:(CDVInvokedUrlCommand*)command;
+-(void)beginLogPageView:(CDVInvokedUrlCommand*)command;
+
+//设置角标到服务器,服务器下一次发消息时,会设置成这个值
+//本接口不会改变应用本地的角标值.
+-(void)setBadge:(CDVInvokedUrlCommand*)command;
+//相当于 [setBadge:0]
+-(void)resetBadge:(CDVInvokedUrlCommand*)command;
+
+//应用本地的角标值设置/获取
+-(void)setApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command;
+-(void)getApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command;
+
+//停止与恢复推送
+-(void)stopPush:(CDVInvokedUrlCommand*)command;
+-(void)resumePush:(CDVInvokedUrlCommand*)command;
+-(void)isPushStopped:(CDVInvokedUrlCommand*)command;
+
+//开关日志
+-(void)setDebugModeFromIos:(CDVInvokedUrlCommand*)command;
+-(void)setLogOFF:(CDVInvokedUrlCommand*)command;
+-(void)crashLogON:(CDVInvokedUrlCommand*)command;
+
+//本地推送
+-(void)setLocalNotification:(CDVInvokedUrlCommand*)command;
+-(void)deleteLocalNotificationWithIdentifierKey:(CDVInvokedUrlCommand*)command;
+-(void)clearAllLocalNotifications:(CDVInvokedUrlCommand*)command;
+
+//地理位置上报 [latitude,longitude]
+-(void)setLocation:(CDVInvokedUrlCommand*)command;
+
+//检查用户的推送设置情况
+-(void)getUserNotificationSettings:(CDVInvokedUrlCommand*)command;
+
+//ios 10 APIs
+-(void)addDismissActions:(CDVInvokedUrlCommand*)command;
+-(void)addNotificationActions:(CDVInvokedUrlCommand*)command;
+
+/*
+ * 以下为js中可监听到的事件
+ * jpush.openNotification 点击推送消息启动或唤醒app
+ * jpush.receiveMessage 收到自定义消息
+ * jpush.receiveNotification 前台收到推送
+ * jpush.backgroundNotification 后台收到推送
+ */
+
+# pragma mark - private
+
++(void)fireDocumentEvent:(NSString*)eventName jsString:(NSString*)jsString;
+
++(void)setupJPushSDK:(NSDictionary*)userInfo;
+
+@end
+
+static JPushPlugin *SharedJPushPlugin;
+
+@interface NSDictionary (JPush)
+-(NSString*)toJsonString;
+@end
+
+@interface NSString (JPush)
+-(NSDictionary*)toDictionary;
+@end
+
+
--- /dev/null
+#import "JPushPlugin.h"
+#import "JPUSHService.h"
+#import <UIKit/UIKit.h>
+#import <AdSupport/AdSupport.h>
+#import <UserNotifications/UserNotifications.h>
+#import "AppDelegate+JPush.h"
+#import "JPushDefine.h"
+
+@implementation NSDictionary (JPush)
+-(NSString*)toJsonString{
+ NSError *error;
+ NSData *data = [NSJSONSerialization dataWithJSONObject:self options:0 error:&error];
+ NSString *jsonString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
+ return jsonString;
+}
+@end
+
+@implementation NSString (JPush)
+-(NSDictionary*)toDictionary{
+ NSError *error;
+ NSData *jsonData = [self dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
+ return dict;
+}
+@end
+
+@interface JPushPlugin()
+
+@end
+
+@implementation JPushPlugin
+
+-(void)startJPushSDK:(CDVInvokedUrlCommand*)command{
+ [(AppDelegate*)[UIApplication sharedApplication].delegate startJPushSDK];
+}
+
+#pragma mark- 外部接口
+-(void)stopPush:(CDVInvokedUrlCommand*)command{
+ [[UIApplication sharedApplication]unregisterForRemoteNotifications];
+}
+
+-(void)resumePush:(CDVInvokedUrlCommand*)command{
+ [(AppDelegate*)[UIApplication sharedApplication].delegate registerForRemoteNotification];
+}
+
+-(void)isPushStopped:(CDVInvokedUrlCommand*)command{
+ NSNumber *result = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications] ? @(0) : @(1);
+ [self handleResultWithValue:result command:command];
+}
+
+-(void)initial:(CDVInvokedUrlCommand*)command{
+ //do nithng,because Cordova plugin use lazy load mode.
+}
+
+#ifdef __CORDOVA_4_0_0
+
+- (void)pluginInitialize {
+ NSLog(@"### pluginInitialize ");
+ [self initPlugin];
+}
+
+#else
+
+- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView{
+ NSLog(@"### initWithWebView ");
+ if (self=[super initWithWebView:theWebView]) {
+ }
+ [self initPlugin];
+ return self;
+}
+
+#endif
+
+-(void)initPlugin{
+ if (!SharedJPushPlugin) {
+ SharedJPushPlugin = self;
+ }
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(networkDidReceiveMessage:)
+ name:kJPFNetworkDidReceiveMessageNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(receiveLocalNotification:)
+ name:JPushDocumentEvent_ReceiveLocalNotification
+ object:nil];
+ [self dispatchJPushCacheEvent];
+}
+
+- (void)dispatchJPushCacheEvent {
+ for (NSString* key in _jpushEventCache) {
+ NSArray *evenList = _jpushEventCache[key];
+ for (NSString *event in evenList) {
+ [JPushPlugin fireDocumentEvent:key jsString:event];
+ }
+ }
+}
+
++(void)fireDocumentEvent:(NSString*)eventName jsString:(NSString*)jsString{
+ if (SharedJPushPlugin) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [SharedJPushPlugin.commandDelegate evalJs:[NSString stringWithFormat:@"cordova.fireDocumentEvent('jpush.%@',%@)", eventName, jsString]];
+ });
+ return;
+ }
+
+ if (!_jpushEventCache) {
+ _jpushEventCache = @{}.mutableCopy;
+ }
+
+ if (!_jpushEventCache[eventName]) {
+ _jpushEventCache[eventName] = @[].mutableCopy;
+ }
+
+ [_jpushEventCache[eventName] addObject: jsString];
+}
+
+-(void)setTags:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService setTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)addTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService addTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)deleteTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSArray* tags = params[@"tags"];
+
+ [JPUSHService deleteTags:[NSSet setWithArray:tags]
+ completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)cleanTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService cleanTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getAllTags:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService getAllTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:[iTags allObjects] forKey:@"tags"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)checkTagBindState:(CDVInvokedUrlCommand *)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSString* tag = params[@"tag"];
+
+ [JPUSHService validTag:tag completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq, BOOL isBind) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ dic[@"tag"] = tag;
+ [dic setObject:[NSNumber numberWithBool:isBind] forKey:@"isBind"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)setAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+ NSString* alias = params[@"alias"];
+
+ [JPUSHService setAlias:alias completion:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:iAlias forKey:@"alias"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)deleteAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService deleteAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getAlias:(CDVInvokedUrlCommand*)command {
+ NSDictionary* params = [command.arguments objectAtIndex:0];
+ NSNumber* sequence = params[@"sequence"];
+
+ [JPUSHService getAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) {
+ NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
+ [dic setObject:sequence forKey:@"sequence"];
+
+ CDVPluginResult* result;
+
+ if (iResCode == 0) {
+ [dic setObject:iAlias forKey:@"alias"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
+ } else {
+ [dic setValue:[NSNumber numberWithUnsignedInteger:iResCode] forKey:@"code"];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:dic];
+ }
+
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ } seq:[sequence integerValue]];
+}
+
+-(void)getRegistrationID:(CDVInvokedUrlCommand*)command{
+ NSString* registrationID = [JPUSHService registrationID];
+ [self handleResultWithValue:registrationID command:command];
+}
+
+-(void)startLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString * pageName = [command argumentAtIndex:0];
+ [JPUSHService startLogPageView:pageName];
+}
+
+-(void)stopLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString * pageName = [command argumentAtIndex:0];
+ [JPUSHService stopLogPageView:pageName];
+}
+
+-(void)beginLogPageView:(CDVInvokedUrlCommand*)command{
+ NSString *pageName = [command argumentAtIndex:0];
+ NSNumber *duration = [command argumentAtIndex:1];
+ [JPUSHService beginLogPageView:pageName duration:duration.intValue];
+}
+
+-(void)setBadge:(CDVInvokedUrlCommand*)command{
+ NSNumber *badge = [command argumentAtIndex:0];
+ [JPUSHService setBadge:badge.intValue];
+}
+
+-(void)resetBadge:(CDVInvokedUrlCommand*)command{
+ [JPUSHService resetBadge];
+}
+
+-(void)setApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command{
+ NSNumber *badge = [command argumentAtIndex:0];
+ [UIApplication sharedApplication].applicationIconBadgeNumber = badge.intValue;
+}
+
+-(void)getApplicationIconBadgeNumber:(CDVInvokedUrlCommand*)command {
+ NSInteger num = [UIApplication sharedApplication].applicationIconBadgeNumber;
+ NSNumber *number = [NSNumber numberWithInteger:num];
+ [self handleResultWithValue:number command:command];
+}
+
+-(void)setDebugModeFromIos:(CDVInvokedUrlCommand*)command{
+ [JPUSHService setDebugMode];
+}
+
+-(void)setLogOFF:(CDVInvokedUrlCommand*)command{
+ [JPUSHService setLogOFF];
+}
+
+-(void)crashLogON:(CDVInvokedUrlCommand*)command{
+ [JPUSHService crashLogON];
+}
+
+-(void)setLocalNotification:(CDVInvokedUrlCommand*)command{
+ NSNumber *delay = [command argumentAtIndex:0];
+ NSString *alert = [command argumentAtIndex:1];
+ NSNumber *badge = [command argumentAtIndex:2];
+ NSString *idKey = [command argumentAtIndex:3];
+ NSDictionary *userInfo = [command argumentAtIndex:4];
+
+ JPushNotificationContent *content = [[JPushNotificationContent alloc] init];
+
+ if (alert) {
+ content.body = alert;
+ }
+
+ if (badge) {
+ content.badge = badge;
+ }
+
+ if (userInfo) {
+ content.userInfo = userInfo;
+ }
+
+ JPushNotificationTrigger *trigger = [[JPushNotificationTrigger alloc] init];
+ // 由于 不支持 0 作为传入参数,在传入参数基础上添加一个极小的时间于 android 端保持一致。
+ if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
+ if (delay) {
+ trigger.timeInterval = [delay doubleValue] + 0.000001;
+ }
+ } else {
+ if (delay) {
+ trigger.fireDate = [NSDate dateWithTimeIntervalSinceNow:[[command argumentAtIndex:0] doubleValue] + 0.001];
+ }
+ }
+
+ JPushNotificationRequest *request = [[JPushNotificationRequest alloc] init];
+ request.content = content;
+ request.trigger = trigger;
+
+ if (idKey) {
+ request.requestIdentifier = idKey;
+ }
+
+ request.completionHandler = ^(id result) {
+ NSLog(@"result");
+ };
+
+ [JPUSHService addNotification:request];
+}
+
+-(void)deleteLocalNotificationWithIdentifierKey:(CDVInvokedUrlCommand*)command{
+ NSString *identifier = [command argumentAtIndex:0];
+ JPushNotificationIdentifier *jpid = [JPushNotificationIdentifier new];
+ jpid.identifiers = @[identifier];
+ [JPUSHService removeNotification:jpid];
+}
+
+-(void)clearAllLocalNotifications:(CDVInvokedUrlCommand*)command{
+ [JPUSHService removeNotification:nil];
+}
+
+-(void)setLocation:(CDVInvokedUrlCommand*)command{
+ NSNumber *latitude = [command argumentAtIndex:0];
+ NSNumber *longitude = [command argumentAtIndex:1];
+ [JPUSHService setLatitude:latitude.doubleValue longitude:longitude.doubleValue];
+}
+
+-(void)getUserNotificationSettings:(CDVInvokedUrlCommand*)command{
+ if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
+ WEAK_SELF(weakSelf);
+ [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
+ NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+ dict[@"authorizationStatus"] = @(settings.authorizationStatus);
+ dict[@"soundSetting"] = @(settings.soundSetting);
+ dict[@"badgeSetting"] = @(settings.badgeSetting);
+ dict[@"alertSetting"] = @(settings.alertSetting);
+ dict[@"notificationCenterSetting"] = @(settings.notificationCenterSetting);
+ dict[@"lockScreenSetting"] = @(settings.lockScreenSetting);
+ dict[@"carPlaySetting"] = @(settings.carPlaySetting);
+ dict[@"alertStyle"] = @(settings.alertStyle);
+ [weakSelf handleResultWithValue:dict command:command];
+ }];
+ }else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
+ UIUserNotificationSettings *settings = [[UIApplication sharedApplication] currentUserNotificationSettings];
+ UIUserNotificationType type = settings.types;
+ NSNumber *number = [NSNumber numberWithInteger:type];
+ [self handleResultWithValue:number command:command];
+ }else{
+ UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
+ NSNumber *number = [NSNumber numberWithInteger:type];
+ [self handleResultWithValue:number command:command];
+ }
+}
+
+#pragma mark - ios 10 APIs
+
+-(void)addDismissActions:(CDVInvokedUrlCommand*)command{
+ [self addActions:command dismiss:YES];
+}
+
+-(void)addNotificationActions:(CDVInvokedUrlCommand*)command{
+ [self addActions:command dismiss:NO];
+}
+
+-(void)addActions:(CDVInvokedUrlCommand*)command dismiss:(BOOL)dimiss{
+ NSArray *actionsData = [command argumentAtIndex:0];
+ NSString *categoryId = [command argumentAtIndex:1];
+ NSMutableArray *actions = [NSMutableArray array];
+ for (NSDictionary *dict in actionsData) {
+ NSString *title = dict[@"title"];
+ NSString *identifier = dict[@"identifier"];
+ NSString *option = dict[@"option"];
+ NSString *type = dict[@"type"];
+ if ([type isEqualToString:@"textInput"]) {
+ NSString *textInputButtonTitle = dict[@"textInputButtonTitle"];
+ NSString *textInputPlaceholder = dict[@"textInputPlaceholder"];
+ UNTextInputNotificationAction *inputAction = [UNTextInputNotificationAction actionWithIdentifier:identifier title:title options:option.integerValue textInputButtonTitle:textInputButtonTitle textInputPlaceholder:textInputPlaceholder];
+ [actions addObject:inputAction];
+ } else {
+ UNNotificationAction *action = [UNNotificationAction actionWithIdentifier:title title:title options:option.integerValue];
+ [actions addObject:action];
+ }
+ }
+ UNNotificationCategory *category;
+ if (dimiss) {
+ category = [UNNotificationCategory categoryWithIdentifier:categoryId
+ actions:actions
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionCustomDismissAction];
+ } else {
+ category = [UNNotificationCategory categoryWithIdentifier:categoryId
+ actions:actions
+ intentIdentifiers:@[]
+ options:UNNotificationCategoryOptionNone];
+ }
+ [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:[NSSet setWithObject:category]];
+}
+
+#pragma mark - 内部方法
+
++(void)setupJPushSDK:(NSDictionary*)userInfo{
+ NSString *plistPath = [[NSBundle mainBundle] pathForResource:JPushConfig_FileName ofType:@"plist"];
+ if (plistPath == nil) {
+ NSLog(@"error: PushConfig.plist not found");
+ assert(0);
+ }
+
+ NSMutableDictionary *plistData = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
+ NSString *appkey = [plistData valueForKey:JPushConfig_Appkey];
+ NSString *channel = [plistData valueForKey:JPushConfig_Channel];
+ NSNumber *isProduction = [plistData valueForKey:JPushConfig_IsProduction];
+ NSNumber *isIDFA = [plistData valueForKey:JPushConfig_IsIDFA];
+
+ NSString *advertisingId = nil;
+ if(isIDFA.boolValue) {
+ advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
+ }
+ [JPUSHService setupWithOption:userInfo
+ appKey:appkey
+ channel:channel
+ apsForProduction:[isProduction boolValue]
+ advertisingIdentifier:advertisingId];
+}
+
+#pragma mark 将参数返回给js
+-(void)handleResultWithValue:(id)value command:(CDVInvokedUrlCommand*)command {
+ CDVPluginResult *result = nil;
+ CDVCommandStatus status = CDVCommandStatus_OK;
+
+ if ([value isKindOfClass:[NSString class]]) {
+ value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ } else if ([value isKindOfClass:[NSNull class]]) {
+ value = nil;
+ }
+
+ if ([value isKindOfClass:[NSObject class]]) {
+ result = [CDVPluginResult resultWithStatus:status messageAsString:value];//NSObject 类型都可以
+ } else {
+ NSLog(@"Cordova callback block returned unrecognized type: %@", NSStringFromClass([value class]));
+ result = nil;
+ }
+
+ if (!result) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
+ }
+ [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+}
+
+-(void)networkDidReceiveMessage:(NSNotification *)notification {
+ if (notification && notification.userInfo) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveMessage
+ jsString:[notification.userInfo toJsonString]];
+ }
+}
+
+-(void)receiveLocalNotification:(NSNotification *)notification {
+ if (notification && notification.object) {
+ [JPushPlugin fireDocumentEvent:JPushDocumentEvent_ReceiveLocalNotification
+ jsString:[notification.object toJsonString]];
+ }
+}
+@end
--- /dev/null
+/*
+ * | | | | \ \ / / | | | | / _______|
+ * | |____| | \ \/ / | |____| | / /
+ * | |____| | \ / | |____| | | | _____
+ * | | | | / \ | | | | | | |____ |
+ * | | | | / /\ \ | | | | \ \______| |
+ * | | | | /_/ \_\ | | | | \_________|
+ *
+ * Copyright (c) 2011 ~ 2017 Shenzhen HXHG. All rights reserved.
+ */
+
+#define JPUSH_VERSION_NUMBER 3.2.1
+
+#import <Foundation/Foundation.h>
+
+@class CLRegion;
+@class UILocalNotification;
+@class CLLocation;
+@class UNNotificationCategory;
+@class UNNotificationSettings;
+@class UNNotificationRequest;
+@class UNNotification;
+@protocol JPUSHRegisterDelegate;
+@protocol JPUSHGeofenceDelegate;
+
+typedef void (^JPUSHTagsOperationCompletion)(NSInteger iResCode, NSSet *iTags, NSInteger seq);
+typedef void (^JPUSHTagValidOperationCompletion)(NSInteger iResCode, NSSet *iTags, NSInteger seq, BOOL isBind);
+typedef void (^JPUSHAliasOperationCompletion)(NSInteger iResCode, NSString *iAlias, NSInteger seq);
+
+extern NSString *const kJPFNetworkIsConnectingNotification; // 正在连接中
+extern NSString *const kJPFNetworkDidSetupNotification; // 建立连接
+extern NSString *const kJPFNetworkDidCloseNotification; // 关闭连接
+extern NSString *const kJPFNetworkDidRegisterNotification; // 注册成功
+extern NSString *const kJPFNetworkFailedRegisterNotification; //注册失败
+extern NSString *const kJPFNetworkDidLoginNotification; // 登录成功
+extern NSString *const kJPFNetworkDidReceiveMessageNotification; // 收到消息(非APNS)
+extern NSString *const kJPFServiceErrorNotification; // 错误提示
+
+typedef NS_OPTIONS(NSUInteger, JPAuthorizationOptions) {
+ JPAuthorizationOptionNone = 0, // the application may not present any UI upon a notification being received
+ JPAuthorizationOptionBadge = (1 << 0), // the application may badge its icon upon a notification being received
+ JPAuthorizationOptionSound = (1 << 1), // the application may play a sound upon a notification being received
+ JPAuthorizationOptionAlert = (1 << 2), // the application may display an alert upon a notification being received
+ JPAuthorizationOptionCarPlay = (1 << 3), // The ability to display notifications in a CarPlay environment.
+ JPAuthorizationOptionCriticalAlert NS_AVAILABLE_IOS(12.0) = (1 << 4) , //The ability to play sounds for critical alerts.
+ JPAuthorizationOptionProvidesAppNotificationSettings NS_AVAILABLE_IOS(12.0) = (1 << 5) , //An option indicating the system should display a button for in-app notification settings.
+ JPAuthorizationOptionProvisional NS_AVAILABLE_IOS(12.0) = (1 << 6) , //The ability to post noninterrupting notifications provisionally to the Notification Center.
+
+};
+
+/*!
+ * 通知注册实体类
+ */
+@interface JPUSHRegisterEntity : NSObject
+
+/*!
+ * 支持的类型
+ * badge,sound,alert
+ */
+@property (nonatomic, assign) NSInteger types;
+/*!
+ * 注入的类别
+ * iOS10 UNNotificationCategory
+ * iOS8-iOS9 UIUserNotificationCategory
+ */
+@property (nonatomic, strong) NSSet *categories;
+@end
+
+/*!
+ * 进行删除、查找推送实体类
+ */
+@interface JPushNotificationIdentifier : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSArray<NSString *> *identifiers; // 推送的标识数组
+@property (nonatomic, copy) UILocalNotification *notificationObj NS_DEPRECATED_IOS(4_0, 10_0); // iOS10以下可以传UILocalNotification对象数据,iOS10以上无效
+@property (nonatomic, assign) BOOL delivered NS_AVAILABLE_IOS(10_0); // 在通知中心显示的或待推送的标志,默认为NO,YES表示在通知中心显示的,NO表示待推送的
+@property (nonatomic, copy) void (^findCompletionHandler)(NSArray *results); // 用于查询回调,调用[findNotification:]方法前必须设置,results为返回相应对象数组,iOS10以下返回UILocalNotification对象数组;iOS10以上根据delivered传入值返回UNNotification或UNNotificationRequest对象数组(delivered传入YES,则返回UNNotification对象数组,否则返回UNNotificationRequest对象数组)
+
+@end
+
+/*!
+ * 推送通知声音实体类
+ * iOS10以上有效
+ */
+@interface JPushNotificationSound : NSObject <NSCopying, NSCoding>
+@property (nonatomic, copy) NSString *soundName; //普通通知铃声
+@property (nonatomic, copy) NSString *criticalSoundName NS_AVAILABLE_IOS(12.0); //警告通知铃声
+@property (nonatomic, assign) float criticalSoundVolume NS_AVAILABLE_IOS(12.0); //警告通知铃声音量,有效值在0~1之间,默认为1
+@end
+
+
+/*!
+ * 推送内容实体类
+ */
+@interface JPushNotificationContent : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSString *title; // 推送标题
+@property (nonatomic, copy) NSString *subtitle; // 推送副标题
+@property (nonatomic, copy) NSString *body; // 推送内容
+@property (nonatomic, copy) NSNumber *badge; // 角标的数字。如果不需要改变角标传@(-1)
+@property (nonatomic, copy) NSString *action NS_DEPRECATED_IOS(8_0, 10_0); // 弹框的按钮显示的内容(IOS 8默认为"打开", 其他默认为"启动",iOS10以上无效)
+@property (nonatomic, copy) NSString *categoryIdentifier; // 行为分类标识
+@property (nonatomic, copy) NSDictionary *userInfo; // 本地推送时可以设置userInfo来增加附加信息,远程推送时设置的payload推送内容作为此userInfo
+@property (nonatomic, copy) NSString *sound; // 声音名称,不设置则为默认声音
+@property (nonatomic, copy) JPushNotificationSound *soundSetting NS_AVAILABLE_IOS(10.0); //推送声音实体
+@property (nonatomic, copy) NSArray *attachments NS_AVAILABLE_IOS(10_0); // 附件,iOS10以上有效,需要传入UNNotificationAttachment对象数组类型
+@property (nonatomic, copy) NSString *threadIdentifier NS_AVAILABLE_IOS(10_0); // 线程或与推送请求相关对话的标识,iOS10以上有效,可用来对推送进行分组
+@property (nonatomic, copy) NSString *launchImageName NS_AVAILABLE_IOS(10_0); // 启动图片名,iOS10以上有效,从推送启动时将会用到
+@property (nonatomic, copy) NSString *summaryArgument NS_AVAILABLE_IOS(12.0); //插入到通知摘要中的部分参数。iOS12以上有效。
+@property (nonatomic, assign) NSUInteger summaryArgumentCount NS_AVAILABLE_IOS(12.0); //插入到通知摘要中的项目数。iOS12以上有效。
+
+@end
+
+
+/*!
+ * 推送触发方式实体类
+ * 注:dateComponents、timeInterval、region在iOS10以上可选择其中一个参数传入有效值,如果同时传入值会根据优先级I、II、III使其中一种触发方式生效,fireDate为iOS10以下根据时间触发时须传入的参数
+ */
+@interface JPushNotificationTrigger : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, assign) BOOL repeat; // 设置是否重复,默认为NO
+@property (nonatomic, copy) NSDate *fireDate NS_DEPRECATED_IOS(2_0, 10_0); // 用来设置触发推送的时间,iOS10以上无效
+@property (nonatomic, copy) CLRegion *region NS_AVAILABLE_IOS(8_0); // 用来设置触发推送的位置,iOS8以上有效,iOS10以上优先级为I,应用需要有允许使用定位的授权
+@property (nonatomic, copy) NSDateComponents *dateComponents NS_AVAILABLE_IOS(10_0); // 用来设置触发推送的日期时间,iOS10以上有效,优先级为II
+@property (nonatomic, assign) NSTimeInterval timeInterval NS_AVAILABLE_IOS(10_0); // 用来设置触发推送的时间,iOS10以上有效,优先级为III
+
+@end
+
+/*!
+ * 注册或更新推送实体类
+ */
+@interface JPushNotificationRequest : NSObject<NSCopying, NSCoding>
+
+@property (nonatomic, copy) NSString *requestIdentifier; // 推送请求标识
+@property (nonatomic, copy) JPushNotificationContent *content; // 设置推送的具体内容
+@property (nonatomic, copy) JPushNotificationTrigger *trigger; // 设置推送的触发方式
+@property (nonatomic, copy) void (^completionHandler)(id result); // 注册或更新推送成功回调,iOS10以上成功则result为UNNotificationRequest对象,失败则result为nil;iOS10以下成功result为UILocalNotification对象,失败则result为nil
+
+@end
+
+/*!
+ * JPush 核心头文件
+ */
+@interface JPUSHService : NSObject
+
+
+///----------------------------------------------------
+/// @name Setup 启动相关
+///----------------------------------------------------
+
+
+/*!
+ * @abstract 启动SDK
+ *
+ * @param launchingOption 启动参数.
+ * @param appKey 一个JPush 应用必须的,唯一的标识. 请参考 JPush 相关说明文档来获取这个标识.
+ * @param channel 发布渠道. 可选.
+ * @param isProduction 是否生产环境. 如果为开发状态,设置为 NO; 如果为生产状态,应改为 YES.
+ * App 证书环境取决于profile provision的配置,此处建议与证书环境保持一致.
+ *
+ * @discussion 提供SDK启动必须的参数, 来启动 SDK.
+ * 此接口必须在 App 启动时调用, 否则 JPush SDK 将无法正常工作.
+ */
++ (void)setupWithOption:(NSDictionary *)launchingOption
+ appKey:(NSString *)appKey
+ channel:(NSString *)channel
+ apsForProduction:(BOOL)isProduction;
+
+/*!
+ * @abstract 启动SDK
+ *
+ * @param launchingOption 启动参数.
+ * @param appKey 一个JPush 应用必须的,唯一的标识. 请参考 JPush 相关说明文档来获取这个标识.
+ * @param channel 发布渠道. 可选.
+ * @param isProduction 是否生产环境. 如果为开发状态,设置为 NO; 如果为生产状态,应改为 YES.
+ * App 证书环境取决于profile provision的配置,此处建议与证书环境保持一致.
+ * @param advertisingId 广告标识符(IDFA) 如果不需要使用IDFA,传nil.
+ *
+ * @discussion 提供SDK启动必须的参数, 来启动 SDK.
+ * 此接口必须在 App 启动时调用, 否则 JPush SDK 将无法正常工作.
+ */
++ (void)setupWithOption:(NSDictionary *)launchingOption
+ appKey:(NSString *)appKey
+ channel:(NSString *)channel
+ apsForProduction:(BOOL)isProduction
+ advertisingIdentifier:(NSString *)advertisingId;
+
+
+///----------------------------------------------------
+/// @name APNs about 通知相关
+///----------------------------------------------------
+
+/*!
+ * @abstract 注册要处理的远程通知类型
+ *
+ * @param types 通知类型
+ * @param categories 类别组
+ *
+ */
++ (void)registerForRemoteNotificationTypes:(NSUInteger)types
+ categories:(NSSet *)categories;
+/*!
+ * @abstract 新版本的注册方法(兼容iOS10)
+ *
+ * @param config 注册通知配置
+ * @param delegate 代理
+ *
+ */
++ (void)registerForRemoteNotificationConfig:(JPUSHRegisterEntity *)config delegate:(id<JPUSHRegisterDelegate>)delegate;
+
+
++ (void)registerDeviceToken:(NSData *)deviceToken;
+
+
+/*!
+ * @abstract 处理收到的 APNs 消息
+ */
++ (void)handleRemoteNotification:(NSDictionary *)remoteInfo;
+
+/*!
+ * Tags操作接口
+ * 支持增加/覆盖/删除/清空/查询操作
+ * 详情请参考文档:https://docs.jiguang.cn/jpush/client/iOS/ios_api/)
+ */
+
+/**
+ 增加tags
+
+ @param tags 需要增加的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)addTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 覆盖tags
+ 调用该接口会覆盖用户所有的tags
+
+ @param tags 需要设置的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)setTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 删除指定tags
+
+ @param tags 需要删除的tags集合
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)deleteTags:(NSSet<NSString *> *)tags
+ completion:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 清空所有tags
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)cleanTags:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 查询全部tags
+
+ @param completion 响应回调,请在回调中获取查询结果
+ @param seq 请求序列号
+ */
++ (void)getAllTags:(JPUSHTagsOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 验证tag是否绑定
+
+ @param completion 响应回调,回调中查看是否绑定
+ @param seq 请求序列号
+ */
++ (void)validTag:(NSString *)tag
+ completion:(JPUSHTagValidOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 设置Alias
+
+ @param alias 需要设置的alias
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)setAlias:(NSString *)alias
+ completion:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 删除alias
+
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)deleteAlias:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+/**
+ 查询当前alias
+
+ @param completion 响应回调
+ @param seq 请求序列号
+ */
++ (void)getAlias:(JPUSHAliasOperationCompletion)completion
+ seq:(NSInteger)seq;
+
+
+/*!
+ * @abstract 过滤掉无效的 tags
+ *
+ * @discussion 如果 tags 数量超过限制数量, 则返回靠前的有效的 tags.
+ * 建议设置 tags 前用此接口校验. SDK 内部也会基于此接口来做过滤.
+ */
++ (NSSet *)filterValidTags:(NSSet *)tags;
+
+///----------------------------------------------------
+/// @name Stats 统计功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 开始记录页面停留
+ *
+ * @param pageName 页面名称
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)startLogPageView:(NSString *)pageName __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 停止记录页面停留
+ *
+ * @param pageName 页面
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)stopLogPageView:(NSString *)pageName __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 直接上报在页面的停留时间
+ *
+ * @param pageName 页面
+ * @param seconds 停留的秒数
+ * @discussion JCore 1.1.8 版本后,如需统计页面流,请使用 JAnalytics
+ */
++ (void)beginLogPageView:(NSString *)pageName duration:(int)seconds __attribute__((deprecated("JCore 1.1.8 版本已过期")));
+
+/*!
+ * @abstract 开启Crash日志收集
+ *
+ * @discussion 默认是关闭状态.
+ */
++ (void)crashLogON;
+
+/*!
+ * @abstract 地理位置上报
+ *
+ * @param latitude 纬度.
+ * @param longitude 经度.
+ *
+ */
++ (void)setLatitude:(double)latitude longitude:(double)longitude;
+
+/*!
+ * @abstract 地理位置上报
+ *
+ * @param location 直接传递 CLLocation * 型的地理信息
+ *
+ * @discussion 需要链接 CoreLocation.framework 并且 #import <CoreLocation/CoreLocation.h>
+ */
++ (void)setLocation:(CLLocation *)location;
+
+/**
+ 设置地理围栏的最大个数
+ 默认值为 10 ,iOS系统默认地理围栏最大个数为20
+ @param count 个数 count
+ */
++ (void)setGeofenecMaxCount:(NSInteger)count;
+/**
+ 注册地理围栏的代理
+
+ @param delegate 代理
+ @param launchOptions app启动完成是收到的字段参数
+ */
++ (void)registerLbsGeofenceDelegate:(id<JPUSHGeofenceDelegate>)delegate withLaunchOptions:(NSDictionary *)launchOptions;
+
+/**
+ 删除地理围栏
+
+ @param geofenceId 地理围栏id
+ */
++ (void)removeGeofenceWithIdentifier:(NSString *)geofenceId;
+
+///----------------------------------------------------
+/// @name Local Notification 本地通知
+///----------------------------------------------------
+/*!
+ * @abstract 注册或更新推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param request JPushNotificationRequest类型,设置推送的属性,设置已有推送的request.requestIdentifier即更新已有的推送,否则为注册新推送,更新推送仅仅在iOS10以上有效,结果通过request.completionHandler返回
+ * @discussion 旧的注册本地推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)addNotification:(JPushNotificationRequest *)request;
+
+/*!
+ * @abstract 移除推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param identifier JPushNotificationIdentifier类型,iOS10以上identifier设置为nil,则移除所有在通知中心显示推送和待推送请求,也可以通过设置identifier.delivered和identifier.identifiers来移除相应在通知中心显示推送或待推送请求,identifier.identifiers如果设置为nil或空数组则移除相应标志下所有在通知中心显示推送或待推送请求;iOS10以下identifier设置为nil,则移除所有推送,identifier.delivered属性无效,另外可以通过identifier.notificationObj传入特定推送对象来移除此推送。
+ * @discussion 旧的所有删除推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)removeNotification:(JPushNotificationIdentifier *)identifier;
+
+/*!
+ * @abstract 查找推送 (支持iOS10,并兼容iOS10以下版本)
+ *
+ * JPush 2.1.9新接口
+ * @param identifier JPushNotificationIdentifier类型,iOS10以上可以通过设置identifier.delivered和identifier.identifiers来查找相应在通知中心显示推送或待推送请求,identifier.identifiers如果设置为nil或空数组则返回相应标志下所有在通知中心显示推送或待推送请求;iOS10以下identifier.delivered属性无效,identifier.identifiers如果设置nil或空数组则返回所有未触发的推送。须要设置identifier.findCompletionHandler回调才能得到查找结果,通过(NSArray *results)返回相应对象数组。
+ * @discussion 旧的查找推送接口被废弃,使用此接口可以替换
+ *
+ */
++ (void)findNotification:(JPushNotificationIdentifier *)identifier;
+
+/*!
+ * @abstract 本地推送,最多支持64个
+ *
+ * @param fireDate 本地推送触发的时间
+ * @param alertBody 本地推送需要显示的内容
+ * @param badge 角标的数字。如果不需要改变角标传-1
+ * @param alertAction 弹框的按钮显示的内容(IOS 8默认为"打开", 其他默认为"启动")
+ * @param notificationKey 本地推送标示符
+ * @param userInfo 自定义参数,可以用来标识推送和增加附加信息
+ * @param soundName 自定义通知声音,设置为nil为默认声音
+ *
+ * @discussion 最多支持 64 个定义,此方法被[addNotification:]方法取代
+ */
++ (UILocalNotification *)setLocalNotification:(NSDate *)fireDate
+ alertBody:(NSString *)alertBody
+ badge:(int)badge
+ alertAction:(NSString *)alertAction
+ identifierKey:(NSString *)notificationKey
+ userInfo:(NSDictionary *)userInfo
+ soundName:(NSString *)soundName __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 本地推送 (支持 iOS8 新参数)
+ *
+ * IOS8新参数
+ * @param region 自定义参数
+ * @param regionTriggersOnce 自定义参数
+ * @param category 自定义参数
+ * @discussion 此方法被[addNotification:]方法取代
+ */
++ (UILocalNotification *)setLocalNotification:(NSDate *)fireDate
+ alertBody:(NSString *)alertBody
+ badge:(int)badge
+ alertAction:(NSString *)alertAction
+ identifierKey:(NSString *)notificationKey
+ userInfo:(NSDictionary *)userInfo
+ soundName:(NSString *)soundName
+ region:(CLRegion *)region
+ regionTriggersOnce:(BOOL)regionTriggersOnce
+ category:(NSString *)category NS_AVAILABLE_IOS(8_0) __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 前台展示本地推送
+ *
+ * @param notification 本地推送对象
+ * @param notificationKey 需要前台显示的本地推送通知的标示符
+ *
+ * @discussion 默认App在前台运行时不会进行弹窗,在程序接收通知调用此接口可实现指定的推送弹窗。--iOS10以下还可继续使用,iOS10以上在[UNUserNotificationCenterDelegate willPresentNotification:withCompletionHandler:]方法中调用completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert);即可
+ */
++ (void)showLocalNotificationAtFront:(UILocalNotification *)notification
+ identifierKey:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+/*!
+ * @abstract 删除本地推送定义
+ *
+ * @param notificationKey 本地推送标示符
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)deleteLocalNotificationWithIdentifierKey:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 删除本地推送定义
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)deleteLocalNotification:(UILocalNotification *)localNotification __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 获取指定通知
+ *
+ * @param notificationKey 本地推送标示符
+ * @return 本地推送对象数组, [array count]为0时表示没找到
+ * @discussion 此方法被[findNotification:]方法取代
+ */
++ (NSArray *)findLocalNotificationWithIdentifier:(NSString *)notificationKey __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+/*!
+ * @abstract 清除所有本地推送对象
+ * @discussion 此方法被[removeNotification:]方法取代
+ */
++ (void)clearAllLocalNotifications __attribute__((deprecated("JPush 2.1.9 版本已过期")));
+
+
+///----------------------------------------------------
+/// @name Server badge 服务器端 badge 功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 设置角标(到服务器)
+ *
+ * @param value 新的值. 会覆盖服务器上保存的值(这个用户)
+ *
+ * @discussion 本接口不会改变应用本地的角标值.
+ * 本地仍须调用 UIApplication:setApplicationIconBadgeNumber 函数来设置脚标.
+ *
+ * 本接口用于配合 JPush 提供的服务器端角标功能.
+ * 该功能解决的问题是, 服务器端推送 APNs 时, 并不知道客户端原来已经存在的角标是多少, 指定一个固定的数字不太合理.
+ *
+ * JPush 服务器端脚标功能提供:
+ *
+ * - 通过本 API 把当前客户端(当前这个用户的) 的实际 badge 设置到服务器端保存起来;
+ * - 调用服务器端 API 发 APNs 时(通常这个调用是批量针对大量用户),
+ * 使用 "+1" 的语义, 来表达需要基于目标用户实际的 badge 值(保存的) +1 来下发通知时带上新的 badge 值;
+ */
++ (BOOL)setBadge:(NSInteger)value;
+
+/*!
+ * @abstract 重置脚标(为0)
+ *
+ * @discussion 相当于 [setBadge:0] 的效果.
+ * 参考 [JPUSHService setBadge:] 说明来理解其作用.
+ */
++ (void)resetBadge;
+
+///----------------------------------------------------
+/// @name Other Feature 其他功能
+///----------------------------------------------------
+
+/*!
+ * @abstract 设置手机号码(到服务器)
+ *
+ * @param mobileNumber 手机号码. 会与用户信息一一对应。可为空,为空则清除号码
+ * @param completion 响应回调。成功则error为空,失败则error带有错误码及错误信息
+ *
+ * @discussion 设置手机号码后,可实现“推送不到短信到”的通知方式,提高推送达到率。结果信息通过completion异步返回,也可将completion设置为nil不处理结果信息。
+ *
+ */
++ (void)setMobileNumber:(NSString *)mobileNumber completion:(void (^)(NSError *error))completion;
+
+///----------------------------------------------------
+/// @name Logs and others 日志与其他
+///----------------------------------------------------
+
+/*!
+ * @abstract JPush标识此设备的 registrationID
+ *
+ * @discussion SDK注册成功后, 调用此接口获取到 registrationID 才能够获取到.
+ *
+ * JPush 支持根据 registrationID 来进行推送.
+ * 如果你需要此功能, 应该通过此接口获取到 registrationID 后, 上报到你自己的服务器端, 并保存下来.
+ * registrationIDCompletionHandler:是新增的获取registrationID的方法,需要在block中获取registrationID,resCode为返回码,模拟器调用此接口resCode返回1011,registrationID返回nil.
+ * 更多的理解请参考 JPush 的文档网站.
+ */
++ (NSString *)registrationID;
+
++ (void)registrationIDCompletionHandler:(void(^)(int resCode,NSString *registrationID))completionHandler;
+
+/*!
+ * @abstract 打开日志级别到 Debug
+ *
+ * @discussion JMessage iOS 的日志系统参考 Android 设计了级别.
+ * 从低到高是: Verbose, Debug, Info, Warning, Error.
+ * 对日志级别的进一步理解, 请参考 Android 相关的说明.
+ *
+ * SDK 默认开启的日志级别为: Info. 只显示必要的信息, 不打印调试日志.
+ *
+ * 请在SDK启动后调用本接口,调用本接口可打开日志级别为: Debug, 打印调试日志.
+ */
++ (void)setDebugMode;
+
+/*!
+ * @abstract 关闭日志
+ *
+ * @discussion 关于日志级别的说明, 参考 [JPUSHService setDebugMode]
+ *
+ * 虽说是关闭日志, 但还是会打印 Warning, Error 日志. 这二种日志级别, 在程序运行正常时, 不应有打印输出.
+ *
+ * 建议在发布的版本里, 调用此接口, 关闭掉日志打印.
+ */
++ (void)setLogOFF;
+
+///----------------------------------------------------
+///********************下列方法已过期********************
+///**************请使用新版tag/alias操作接口**************
+///----------------------------------------------------
+/// @name Tag alias setting 设置别名与标签
+///----------------------------------------------------
+
+/*!
+ * 下面的接口是可选的
+ * 设置标签和(或)别名(若参数为nil,则忽略;若是空对象,则清空;详情请参考文档:https://docs.jiguang.cn/jpush/client/iOS/ios_api/)
+ * setTags:alias:fetchCompletionHandle:是新的设置标签别名的方法,不再需要显示声明回调函数,只需要在block里面处理设置结果即可.
+ * WARN: 使用block时需要注意循环引用问题
+ */
++ (void) setTags:(NSSet *)tags
+ alias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ target:(id)theTarget __attribute__((deprecated("JPush 2.1.1 版本已过期")));
++ (void) setTags:(NSSet *)tags
+ alias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void) setTags:(NSSet *)tags
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void)setTags:(NSSet *)tags
+ alias:(NSString *)alias
+fetchCompletionHandle:(void (^)(int iResCode, NSSet *iTags, NSString *iAlias))completionHandler __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void) setTags:(NSSet *)tags
+aliasInbackground:(NSString *)alias __attribute__((deprecated("JPush 3.0.6 版本已过期")));
++ (void)setAlias:(NSString *)alias
+callbackSelector:(SEL)cbSelector
+ object:(id)theTarget __attribute__((deprecated("JPush 3.0.6 版本已过期")));
+
+@end
+
+@class UNUserNotificationCenter;
+@class UNNotificationResponse;
+
+@protocol JPUSHRegisterDelegate <NSObject>
+
+/*
+ * @brief handle UserNotifications.framework [willPresentNotification:withCompletionHandler:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param notification 前台得到的的通知对象
+ * @param completionHandler 该callback中的options 请使用UNNotificationPresentationOptions
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger options))completionHandler;
+/*
+ * @brief handle UserNotifications.framework [didReceiveNotificationResponse:withCompletionHandler:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param response 通知响应对象
+ * @param completionHandler
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler;
+
+/*
+ * @brief handle UserNotifications.framework [openSettingsForNotification:]
+ * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
+ * @param notification 当前管理的通知对象
+ */
+- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification NS_AVAILABLE_IOS(12.0);
+
+@end
+
+@protocol JPUSHGeofenceDelegate <NSObject>
+
+/**
+ 进入地理围栏区域
+
+ @param geofenceId 地理围栏id
+ @param userInfo 地理围栏触发时返回的信息
+ @param error 错误信息
+ */
+- (void)jpushGeofenceIdentifer:(NSString * _Nonnull)geofenceId didEnterRegion:(NSDictionary * _Nullable)userInfo error:(NSError * _Nullable)error;
+
+/**
+ 离开地理围栏区域
+
+ @param geofenceId 地理围栏id
+ @param userInfo 地理围栏触发时返回的信息
+ @param error 错误信息
+ */
+- (void)jpushGeofenceIdentifer:(NSString * _Nonnull)geofenceId didExitRegion:(NSDictionary * _Nullable)userInfo error:(NSError * _Nullable)error;
+
+@end
--- /dev/null
+//
+// NotificationService.h
+// jpushNotificationService
+//
+// Created by wuxingchen on 16/10/10.
+//
+//
+
+#import <UserNotifications/UserNotifications.h>
+
+@interface NotificationService : UNNotificationServiceExtension
+
+@end
--- /dev/null
+//
+// NotificationService.m
+// jpushNotificationService
+//
+// Created by wuxingchen on 16/10/10.
+//
+//
+
+#import "NotificationService.h"
+#import <UIKit/UIKit.h>
+
+@interface NotificationService ()
+
+@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
+@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
+
+@end
+
+@implementation NotificationService
+
+- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
+
+ self.contentHandler = contentHandler;
+ self.bestAttemptContent = [request.content mutableCopy];
+
+ @try {
+ NSString *urlStr = [request.content.userInfo valueForKey:@"JPushPluginAttachment"];
+ NSArray *urls = [urlStr componentsSeparatedByString:@"."];
+ NSURL *urlNative = [[NSBundle mainBundle] URLForResource:urls[0] withExtension:urls[1]];
+ UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:urlStr URL:urlNative options:nil error:nil];
+ self.bestAttemptContent.attachments = @[attachment];
+ } @catch (NSException *exception) {
+ }
+
+ self.contentHandler(self.bestAttemptContent);
+}
+
+- (void)serviceExtensionTimeWillExpire {
+ // Called just before the extension will be terminated by the system.
+ // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
+ self.contentHandler(self.bestAttemptContent);
+}
+
+@end
--- /dev/null
+var JPushPlugin = function() {};
+
+// private plugin function
+
+JPushPlugin.prototype.receiveMessage = {};
+JPushPlugin.prototype.openNotification = {};
+JPushPlugin.prototype.receiveNotification = {};
+
+JPushPlugin.prototype.isPlatformIOS = function() {
+ return (
+ device.platform === "iPhone" ||
+ device.platform === "iPad" ||
+ device.platform === "iPod touch" ||
+ device.platform === "iOS"
+ );
+};
+
+JPushPlugin.prototype.errorCallback = function(msg) {
+ console.log("JPush Callback Error: " + msg);
+};
+
+JPushPlugin.prototype.callNative = function(
+ name,
+ args,
+ successCallback,
+ errorCallback
+) {
+ if (errorCallback) {
+ cordova.exec(successCallback, errorCallback, "JPushPlugin", name, args);
+ } else {
+ cordova.exec(
+ successCallback,
+ this.errorCallback,
+ "JPushPlugin",
+ name,
+ args
+ );
+ }
+};
+
+// Common methods
+JPushPlugin.prototype.init = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("initial", [], null);
+ } else {
+ this.callNative("init", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugMode = function(mode) {
+ if (device.platform === "Android") {
+ this.callNative("setDebugMode", [mode], null);
+ } else {
+ if (mode === true) {
+ this.setDebugModeFromIos();
+ } else {
+ this.setLogOFF();
+ }
+ }
+};
+
+JPushPlugin.prototype.getRegistrationID = function(successCallback) {
+ this.callNative("getRegistrationID", [], successCallback);
+};
+
+JPushPlugin.prototype.stopPush = function() {
+ this.callNative("stopPush", [], null);
+};
+
+JPushPlugin.prototype.resumePush = function() {
+ this.callNative("resumePush", [], null);
+};
+
+JPushPlugin.prototype.isPushStopped = function(successCallback) {
+ this.callNative("isPushStopped", [], successCallback);
+};
+
+JPushPlugin.prototype.clearLocalNotifications = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearLocalNotifications", [], null);
+ } else {
+ this.clearAllLocalNotifications();
+ }
+};
+
+/**
+ * 设置标签。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.setTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 新增标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.addTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("addTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除指定标签。
+ *
+ * @param params = { 'sequence': number, 'tags': ['tag1', 'tag2'] }
+ */
+JPushPlugin.prototype.deleteTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 清除所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.cleanTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("cleanTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询所有标签。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAllTags = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAllTags", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询指定标签与当前用户的绑定状态。
+ *
+ * @param params = { 'sequence': number, 'tag': string }
+ */
+JPushPlugin.prototype.checkTagBindState = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative(
+ "checkTagBindState",
+ [params],
+ successCallback,
+ errorCallback
+ );
+};
+
+/**
+ * 设置别名。
+ * 注意:该接口是覆盖逻辑,而不是增量逻辑。即新的调用会覆盖之前的设置。
+ *
+ * @param params = { 'sequence': number, 'alias': string }
+ */
+JPushPlugin.prototype.setAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("setAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 删除别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.deleteAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("deleteAlias", [params], successCallback, errorCallback);
+};
+
+/**
+ * 查询当前绑定的别名。
+ *
+ * @param params = { 'sequence': number }
+ */
+JPushPlugin.prototype.getAlias = function(
+ params,
+ successCallback,
+ errorCallback
+) {
+ this.callNative("getAlias", [params], successCallback, errorCallback);
+};
+
+// 判断系统设置中是否对本应用启用通知。
+// iOS: 返回值如果大于 0,代表通知开启;0: 通知关闭。
+// UIRemoteNotificationTypeNone = 0,
+// UIRemoteNotificationTypeBadge = 1 << 0,
+// UIRemoteNotificationTypeSound = 1 << 1,
+// UIRemoteNotificationTypeAlert = 1 << 2,
+// UIRemoteNotificationTypeNewsstandContentAvailability = 1 << 3,
+// Android: 返回值 1 代表通知启用;0: 通知关闭。
+JPushPlugin.prototype.getUserNotificationSettings = function(successCallback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getUserNotificationSettings", [], successCallback);
+ } else if (device.platform === "Android") {
+ this.callNative("areNotificationEnabled", [], successCallback);
+ }
+};
+
+// iOS methods
+
+JPushPlugin.prototype.startJPushSDK = function() {
+ this.callNative("startJPushSDK", [], null);
+};
+
+JPushPlugin.prototype.setBadge = function(value) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setBadge", [value], null);
+ }
+};
+
+JPushPlugin.prototype.resetBadge = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("resetBadge", [], null);
+ }
+};
+
+JPushPlugin.prototype.setDebugModeFromIos = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setDebugModeFromIos", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLogOFF = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLogOFF", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCrashLogON = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("crashLogON", [], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotificationForIOS = function(
+ delayTime,
+ content,
+ badge,
+ notificationID,
+ extras
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "setLocalNotification",
+ [delayTime, content, badge, notificationID, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.deleteLocalNotificationWithIdentifierKeyInIOS = function(
+ identifierKey
+) {
+ if (this.isPlatformIOS()) {
+ this.callNative(
+ "deleteLocalNotificationWithIdentifierKey",
+ [identifierKey],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.clearAllLocalNotifications = function() {
+ if (this.isPlatformIOS()) {
+ this.callNative("clearAllLocalNotifications", [], null);
+ }
+};
+
+JPushPlugin.prototype.setLocation = function(latitude, longitude) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setLocation", [latitude, longitude], null);
+ }
+};
+
+JPushPlugin.prototype.startLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("startLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.stopLogPageView = function(pageName) {
+ if (this.isPlatformIOS()) {
+ this.callNative("stopLogPageView", [pageName], null);
+ }
+};
+
+JPushPlugin.prototype.beginLogPageView = function(pageName, duration) {
+ if (this.isPlatformIOS()) {
+ this.callNative("beginLogPageView", [pageName, duration], null);
+ }
+};
+
+JPushPlugin.prototype.setApplicationIconBadgeNumber = function(badge) {
+ if (this.isPlatformIOS()) {
+ this.callNative("setApplicationIconBadgeNumber", [badge], null);
+ }
+};
+
+JPushPlugin.prototype.getApplicationIconBadgeNumber = function(callback) {
+ if (this.isPlatformIOS()) {
+ this.callNative("getApplicationIconBadgeNumber", [], callback);
+ }
+};
+
+JPushPlugin.prototype.addDismissActions = function(actions, categoryId) {
+ this.callNative("addDismissActions", [actions, categoryId]);
+};
+
+JPushPlugin.prototype.addNotificationActions = function(actions, categoryId) {
+ this.callNative("addNotificationActions", [actions, categoryId]);
+};
+
+// Android methods
+JPushPlugin.prototype.getConnectionState = function(successCallback) {
+ if (device.platform === "Android") {
+ this.callNative("getConnectionState", [], successCallback);
+ }
+};
+
+JPushPlugin.prototype.setBasicPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setBasicPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.setCustomPushNotificationBuilder = function() {
+ if (device.platform === "Android") {
+ this.callNative("setCustomPushNotificationBuilder", [], null);
+ }
+};
+
+JPushPlugin.prototype.receiveRegistrationIdInAndroidCallback = function(data) {
+ if (device.platform === "Android") {
+ data = JSON.stringify(data);
+ var event = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveRegistrationId", event);
+ }
+};
+
+JPushPlugin.prototype.receiveMessageInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveMessage = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.receiveMessage", this.receiveMessage);
+};
+
+JPushPlugin.prototype.openNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.openNotification = JSON.parse(data);
+ cordova.fireDocumentEvent("jpush.openNotification", this.openNotification);
+};
+
+JPushPlugin.prototype.receiveNotificationInAndroidCallback = function(data) {
+ data = JSON.stringify(data);
+ this.receiveNotification = JSON.parse(data);
+ cordova.fireDocumentEvent(
+ "jpush.receiveNotification",
+ this.receiveNotification
+ );
+};
+
+JPushPlugin.prototype.clearAllNotification = function() {
+ if (device.platform === "Android") {
+ this.callNative("clearAllNotification", [], null);
+ }
+};
+
+JPushPlugin.prototype.clearNotificationById = function(id) {
+ if (device.platform === "Android") {
+ this.callNative("clearNotificationById", [id], null);
+ }
+};
+
+JPushPlugin.prototype.setLatestNotificationNum = function(num) {
+ if (device.platform === "Android") {
+ this.callNative("setLatestNotificationNum", [num], null);
+ }
+};
+
+JPushPlugin.prototype.addLocalNotification = function(
+ builderId,
+ content,
+ title,
+ notificationID,
+ broadcastTime,
+ extras
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "addLocalNotification",
+ [builderId, content, title, notificationID, broadcastTime, extras],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.removeLocalNotification = function(notificationID) {
+ if (device.platform === "Android") {
+ this.callNative("removeLocalNotification", [notificationID], null);
+ }
+};
+
+JPushPlugin.prototype.reportNotificationOpened = function(msgID) {
+ if (device.platform === "Android") {
+ this.callNative("reportNotificationOpened", [msgID], null);
+ }
+};
+
+/**
+ * 用于在 Android 6.0 及以上系统,申请一些权限
+ * 具体可看:http://docs.jpush.io/client/android_api/#android-60
+ */
+JPushPlugin.prototype.requestPermission = function() {
+ if (device.platform === "Android") {
+ this.callNative("requestPermission", [], null);
+ }
+};
+
+JPushPlugin.prototype.setSilenceTime = function(
+ startHour,
+ startMinute,
+ endHour,
+ endMinute
+) {
+ if (device.platform === "Android") {
+ this.callNative(
+ "setSilenceTime",
+ [startHour, startMinute, endHour, endMinute],
+ null
+ );
+ }
+};
+
+JPushPlugin.prototype.setPushTime = function(weekdays, startHour, endHour) {
+ if (device.platform === "Android") {
+ this.callNative("setPushTime", [weekdays, startHour, endHour], null);
+ }
+};
+
+JPushPlugin.prototype.setGeofenceInterval = function(interval) {
+ if (device.platform === "Android") {
+ this.callNative("setGeofenceInterval", [interval], null);
+ }
+};
+
+JPushPlugin.prototype.setMaxGeofenceNumber = function(maxNumber) {
+ if (device.platform === "Android") {
+ this.callNative("setMaxGeofenceNumber", [maxNumber], null);
+ }
+};
+
+if (!window.plugins) {
+ window.plugins = {};
+}
+
+if (!window.plugins.jPushPlugin) {
+ window.plugins.jPushPlugin = new JPushPlugin();
+}
+
+module.exports = new JPushPlugin();
// Application Constructor
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
+ document.addEventListener('jpush.receiveRegistrationId', function (event) {
+ console.log(event.registrationId)
+ }, false)
},
onDeviceReady: function() {