aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mcrute@gmail.com>2016-08-16 19:35:56 -0700
committerMike Crute <mcrute@gmail.com>2016-08-16 19:35:56 -0700
commitb89f5ffb3730c6813dfc864a8045c6b99635604c (patch)
treec5b6bcdef35c19a164e40e2c9da5dd4e44b7770a
parent244e353bb6a788e5f76ed999abf3149704dea754 (diff)
downloadubntmfi-b89f5ffb3730c6813dfc864a8045c6b99635604c.tar.bz2
ubntmfi-b89f5ffb3730c6813dfc864a8045c6b99635604c.tar.xz
ubntmfi-b89f5ffb3730c6813dfc864a8045c6b99635604c.zip
Remove non-core files and cleanup
-rw-r--r--.gitignore1
-rw-r--r--README.md20
-rwxr-xr-xcollect_ssh.py123
-rw-r--r--inform_protocol.md24
-rw-r--r--mfiapi.py58
-rw-r--r--parse_dumped_bodies.py24
-rw-r--r--parse_pcap.py39
-rw-r--r--python/inform.py (renamed from inform.py)7
-rw-r--r--python/noop_server.py (renamed from inform_server.py)0
-rw-r--r--requirements.txt6
-rwxr-xr-xreversing_tools/parse_pcap.py60
-rw-r--r--server.py66
-rw-r--r--static/vendor/images/ajax-loader.gifbin7825 -> 0 bytes
-rw-r--r--static/vendor/images/icons-18-black.pngbin1968 -> 0 bytes
-rw-r--r--static/vendor/images/icons-18-white.pngbin1988 -> 0 bytes
-rw-r--r--static/vendor/images/icons-36-black.pngbin3859 -> 0 bytes
-rw-r--r--static/vendor/images/icons-36-white.pngbin3861 -> 0 bytes
-rw-r--r--static/vendor/jquery-1.10.2.js9789
-rw-r--r--static/vendor/jquery.mobile-1.3.2.css3370
-rw-r--r--static/vendor/jquery.mobile-1.3.2.js11215
-rw-r--r--static/vendor/jquery.mobile.structure-1.3.2.css2314
-rw-r--r--static/vendor/jquery.mobile.theme-1.3.2.css1068
-rw-r--r--templates/index.html51
-rw-r--r--utils.py16
24 files changed, 91 insertions, 28160 deletions
diff --git a/.gitignore b/.gitignore
index 07469ec..7d74eba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
1*.pyc 1*.pyc
2.sandbox_name 2.sandbox_name
3keystore.py 3keystore.py
4/data
diff --git a/README.md b/README.md
index 3d82d73..5a4e94f 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,15 @@
1Ubiquiti mFi Controller 1Ubiquiti mFi Controller
2======================= 2=======================
3This repo contains a python implementation of a parser for the Ubiquiti Inform
4Protocol. This protocol is used by Ubiquiti Unifi access points to communicate
5with the controller for ongoing metrics collection and configuration. It's also
6used in the Ubiquiti mFi products for command and control of light switches,
7power outlets, mPorts and power strips.
3 8
4This repo contains an alternative web controller for the Ubiquiti mFi mPower 9The goal of this library is to build a fully functional replacement for the
5strips. Who knows what could happen here. My initial goal is to provide a 10abandoned Ubiquiti controller. A fully functional python library for inform
6simple mobile site to control the switches. 11parsing and serialization exists in the python directory along with a sample
7 12server that just sends NOOP packets to devices checking in. The python work is
8Installation 13considered finished and will be split into a new repo at some point. All
9============ 14further work will go into a Go (golang) API on which the controller will be
10Run ``pip install -r requirements.txt`` from within a virtualenv then start 15built.
11with ``python server.py``
diff --git a/collect_ssh.py b/collect_ssh.py
deleted file mode 100755
index 607b774..0000000
--- a/collect_ssh.py
+++ /dev/null
@@ -1,123 +0,0 @@
1#!/usr/bin/env python
2
3import os
4import json
5import time
6import paramiko
7import contextlib
8import subprocess
9
10from keystore import USERNAME, PASSWORD, HOSTS
11
12
13RRA_COMMON = [
14 "RRA:AVERAGE:0.5:1:800",
15 "RRA:AVERAGE:0.5:6:800",
16 "RRA:AVERAGE:0.5:24:800",
17 "RRA:AVERAGE:0.5:288:800",
18 "RRA:MAX:0.5:1:800",
19 "RRA:MAX:0.5:6:800",
20 "RRA:MAX:0.5:24:800",
21 "RRA:MAX:0.5:288:800",
22]
23
24RRD_TEMPLATES = {
25 "interface": [
26 "DS:packets_rx:COUNTER:600:0:U",
27 "DS:packets_tx:COUNTER:600:0:U",
28 "DS:bytes_rx:COUNTER:600:0:U",
29 "DS:bytes_tx:COUNTER:600:0:U",
30 "DS:errors_rx:COUNTER:600:0:U",
31 "DS:errors_tx:COUNTER:600:0:U",
32 "DS:dropped_rx:COUNTER:600:0:U",
33 "DS:dropped_tx:COUNTER:600:0:U",
34 ],
35 "network": [
36 "DS:packets_rx:COUNTER:600:0:U",
37 "DS:packets_tx:COUNTER:600:0:U",
38 "DS:bytes_rx:COUNTER:600:0:U",
39 "DS:bytes_tx:COUNTER:600:0:U",
40 "DS:retries_tx:COUNTER:600:0:U",
41 "DS:stations:GAUGE:600:0:U",
42 ],
43 "station": [
44 "DS:rssi:GAUGE:600:0:U",
45 "DS:noise:GAUGE:600:U:U",
46 "DS:signal:GAUGE:600:U:U",
47 "DS:power:GAUGE:600:0:U",
48 "DS:rate_rx:GAUGE:600:0:U",
49 "DS:rate_tx:GAUGE:600:0:U",
50 "DS:packets_rx:COUNTER:600:0:U",
51 "DS:packets_tx:COUNTER:600:0:U",
52 "DS:bytes_rx:COUNTER:600:0:U",
53 "DS:bytes_tx:COUNTER:600:0:U",
54 ],
55}
56
57
58@contextlib.contextmanager
59def get_mca_data(host):
60 client = paramiko.SSHClient()
61 client.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy())
62 client.connect(host, username=USERNAME, password=PASSWORD)
63 _, stdout, _ = client.exec_command("mca-dump")
64
65 yield json.loads(stdout.read())
66
67 client.close()
68
69
70@contextlib.contextmanager
71def host_folder(host):
72 if not os.path.exists(host):
73 os.mkdir(host)
74
75 os.chdir(host)
76 yield
77 os.chdir(os.path.dirname(os.getcwd()))
78
79
80def rrd_update(kind, name, source, *stats):
81 stats = ":".join(["N"] + list(str(int(source[key])) for key in stats))
82 rrd_name = "{}-{}.rrd".format(kind, name)
83
84 if not os.path.exists(rrd_name):
85 command = ["rrdtool", "create", rrd_name]
86 command.extend(RRD_TEMPLATES[kind])
87 command.extend(RRA_COMMON)
88 subprocess.call(command)
89
90 subprocess.call(("rrdtool", "update", rrd_name, stats))
91
92
93def update_eth(data):
94 rrd_update("interface", "eth0", data, "rx_packets", "tx_packets",
95 "rx_bytes", "tx_bytes", "rx_errors", "tx_errors", "rx_errors",
96 "tx_errors")
97
98def update_network(data):
99 rrd_update("network", "{}_{}".format(data["essid"], data["radio"]), data,
100 "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "tx_retries",
101 "num_sta")
102
103
104def update_station(data):
105 rrd_update("station", data["mac"], data, "rssi", "noise", "signal",
106 "tx_power", "rx_rate", "tx_rate", "rx_packets", "tx_packets",
107 "rx_bytes", "tx_bytes")
108
109
110while True:
111 for host in HOSTS:
112 print "Updating {}".format(host)
113 with host_folder(host), get_mca_data(host) as data:
114 update_eth(data["if_table"][0])
115
116 for vap in data["vap_table"]:
117 update_network(vap)
118
119 for station in vap["sta_table"]:
120 update_station(station)
121
122 print "=" * 80
123 time.sleep(300)
diff --git a/inform_protocol.md b/inform_protocol.md
index bb26f36..cadbe24 100644
--- a/inform_protocol.md
+++ b/inform_protocol.md
@@ -9,7 +9,7 @@ disable.
9 9
10Everything appears to be pull-based, even provisioning. This makes sense with 10Everything appears to be pull-based, even provisioning. This makes sense with
11the cloud controller where the controller has no access to your network. I 11the cloud controller where the controller has no access to your network. I
12haven't documented yet how anything works within the protocol, that's next. 12have not documented yet how anything works within the protocol, that is next.
13This documents the overall protocol itself. 13This documents the overall protocol itself.
14 14
15The device will inform by executing an HTTP POST with an encrypted payload to 15The device will inform by executing an HTTP POST with an encrypted payload to
@@ -21,14 +21,14 @@ appear to contain multiple commands.
21 21
22Raw Packet Structure 22Raw Packet Structure
23-------------------- 23--------------------
244 bytes magic number integer 244 bytes magic number integer
254 bytes version integer 254 bytes version integer
266 bytes hwaddr string 266 bytes hwaddr string
272 bytes flags short 272 bytes flags short
2816 bytes initialization vector string 2816 bytes initialization vector string
294 bytes data version integer 294 bytes data version integer
304 bytes data length integer 304 bytes data length integer
31n bytes encrypted payload string 31n bytes AES encrypted payload string
32 32
33Raw Packet Constraints 33Raw Packet Constraints
34---------------------- 34----------------------
@@ -41,7 +41,7 @@ Payload Types
41------------- 41-------------
42The payload is AES encrypted in CBC mode using PKCS5 padding. They key is the 42The payload is AES encrypted in CBC mode using PKCS5 padding. They key is the
43device auth key from the database or a master key that is hard coded if the 43device auth key from the database or a master key that is hard coded if the
44device hasn't been provisioned yet. The master key is hard coded in the 44device has not been provisioned yet. The master key is hard coded in the
45controller code in the DeviceManager class and pretty easy to find. 45controller code in the DeviceManager class and pretty easy to find.
46 46
47MASTER_KEY = "ba86f2bbe107c7c57eb5f2690775c712" 47MASTER_KEY = "ba86f2bbe107c7c57eb5f2690775c712"
@@ -118,8 +118,8 @@ following output payloads.
118Input Payloads 118Input Payloads
119-------------- 119--------------
120Incoming packets appear to be a JSON version of the out put of the `mca-dump` 120Incoming packets appear to be a JSON version of the out put of the `mca-dump`
121command on the device. There is definitely some AirOS legacy in here. I don't 121command on the device. There is definitely some AirOS legacy in here. I do not
122document the whole input payload since most of it isn't interesting. 122document the whole input payload since most of it is not interesting.
123 123
124 callback from device: javascript object 124 callback from device: javascript object
125 alarm: list of sensors 125 alarm: list of sensors
diff --git a/mfiapi.py b/mfiapi.py
deleted file mode 100644
index 31f0330..0000000
--- a/mfiapi.py
+++ /dev/null
@@ -1,58 +0,0 @@
1import json
2import urllib2
3import urllib
4from cookielib import CookieJar
5
6def bool_to_bin(value):
7 return 1 if value == True else 0
8
9
10def bin_to_bool(value):
11 return True if int(value) == 1 else False
12
13
14class MFiAPI(object):
15
16 def __init__(self, host):
17 self.host = host
18 self.opener = urllib2.build_opener(
19 urllib2.HTTPCookieProcessor(CookieJar()))
20
21 def _make_url(self, suffix):
22 return 'https://{}/{}'.format(self.host, suffix)
23
24 def login(self, username, password):
25 form_data = urllib.urlencode({
26 'username' : username,
27 'password': password,
28 'login': 'login'
29 })
30
31 self.opener.open(self._make_url('login'), form_data)
32
33 def get_sensor_data(self):
34 resp = self.opener.open(self._make_url('api/v1.0/list/sensors'))
35 return json.load(resp)['data']
36
37 def port_status(self):
38 data = self.get_sensor_data()
39 return dict((i['label'], bin_to_bool(i['output_val'])) for i in data)
40
41 def set_port(self, mac, port, value):
42 data = urllib.urlencode({ "json": json.dumps({
43 "mac": mac,
44 "val": bool_to_bin(value),
45 "port": int(port),
46 "cmd": "mfi-output"
47 })
48 })
49
50 self.opener.open(self._make_url("api/v1.0/cmd/devmgr"), data)
51
52 def toggle_port(self, name):
53 mac, port, status = None, None, None
54
55 for data in self.get_sensor_data():
56 if data['label'] == name:
57 set_to = not bin_to_bool(data['output_val'])
58 self.set_port(data['mac'], data['port'], set_to)
diff --git a/parse_dumped_bodies.py b/parse_dumped_bodies.py
deleted file mode 100644
index 4275e68..0000000
--- a/parse_dumped_bodies.py
+++ /dev/null
@@ -1,24 +0,0 @@
1import os
2import json
3from keystore import KEYSTORE
4from cStringIO import StringIO
5from inform import InformSerializer, Cryptor
6
7
8PATH = "/Users/mcrute/Desktop/test2"
9
10
11for file in os.listdir(PATH):
12 ser = InformSerializer()
13
14 with open(os.path.join(PATH, file)) as fp:
15 packet = ser.parse(fp)
16
17 ser.key = KEYSTORE[packet.formatted_mac_addr]
18
19 ser._decrypt_payload(packet)
20
21
22 payload = packet.payload
23
24 print json.dumps(payload, sort_keys=True, indent=4)
diff --git a/parse_pcap.py b/parse_pcap.py
deleted file mode 100644
index bcc3e69..0000000
--- a/parse_pcap.py
+++ /dev/null
@@ -1,39 +0,0 @@
1import dpkt
2import json
3import binascii
4from cStringIO import StringIO
5from inform import InformSerializer, Cryptor
6
7
8d = json.load(open("devices.json"))
9KEYSTORE = { i['mac']: i['x_authkey'] for i in d }
10
11
12def add_colons_to_mac(mac_addr):
13 mac_addr = binascii.hexlify(mac_addr)
14 return ":".join([mac_addr[i*2:i*2+2] for i in range(12/2)]).lower()
15
16
17records = []
18buffer = StringIO()
19
20for ts, buf in dpkt.pcap.Reader(open("mfi.out")):
21 eth = dpkt.ethernet.Ethernet(buf)
22 data = eth.data.tcp.data.split("\r\n")[-1]
23
24 if data.startswith("TNBU") and buffer.tell() != 0:
25 records.append(buffer.getvalue())
26 buffer.seek(0)
27 buffer.write(data)
28 else:
29 buffer.write(data)
30
31
32ser = InformSerializer("", KEYSTORE)
33for data in records:
34 try:
35 packet = ser.parse(StringIO(data))
36 print packet.raw_payload
37 except:
38 print "BAD"
39 continue
diff --git a/inform.py b/python/inform.py
index 9877f45..ee47a69 100644
--- a/inform.py
+++ b/python/inform.py
@@ -151,9 +151,6 @@ class InformSerializer(object):
151 self.key_bag = key_bag or {} 151 self.key_bag = key_bag or {}
152 152
153 def _decrypt_payload(self, packet): 153 def _decrypt_payload(self, packet):
154 if not packet.is_encrypted:
155 return
156
157 i = 0 154 i = 0
158 key = self.key_bag.get(packet.formatted_mac_addr) 155 key = self.key_bag.get(packet.formatted_mac_addr)
159 156
@@ -186,7 +183,9 @@ class InformSerializer(object):
186 packet.data_length = input_stream.read_int() 183 packet.data_length = input_stream.read_int()
187 184
188 packet.raw_payload = input_stream.read_string(packet.data_length) 185 packet.raw_payload = input_stream.read_string(packet.data_length)
189 self._decrypt_payload(packet) 186
187 if packet.is_encrypted:
188 self._decrypt_payload(packet)
190 189
191 return packet 190 return packet
192 191
diff --git a/inform_server.py b/python/noop_server.py
index ebe3bda..ebe3bda 100644
--- a/inform_server.py
+++ b/python/noop_server.py
diff --git a/requirements.txt b/requirements.txt
index 3c93d5c..96367e7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,3 @@
1tornado==3.1 1mitmproxy==0.17
2pycrypto==2.6 2pycrypto==2.6.1
3paramiko==1.11.1 3requests==2.9.2
diff --git a/reversing_tools/parse_pcap.py b/reversing_tools/parse_pcap.py
new file mode 100755
index 0000000..c29c1d2
--- /dev/null
+++ b/reversing_tools/parse_pcap.py
@@ -0,0 +1,60 @@
1#!/usr/bin/env python
2
3import dpkt
4import json
5from cStringIO import StringIO
6from inform import InformSerializer
7
8
9def go_debug(filename):
10 arr = lambda x: [ord(i) for i in x]
11 packet = ser.parse(open('test_files/2.bin'))
12 return {
13 "magic": packet.magic_number,
14 "version": packet.version,
15 "mac": arr(packet.mac_addr),
16 "flags": packet.flags,
17 "iv": arr(packet.iv),
18 "data_version": packet.data_version,
19 "data_len": packet.data_length,
20 "raw_payload": json.packet.raw_payload,
21 "formatted_mac": packet.formatted_mac_addr,
22 "is_enc": packet.is_encrypted,
23 "is_comp": packet.is_compressed,
24 }
25
26
27def collect_records(from_file):
28 records = []
29 buffer = StringIO()
30
31 for ts, buf in dpkt.pcap.Reader(open(from_file)):
32 eth = dpkt.ethernet.Ethernet(buf)
33 data = eth.data.tcp.data.split("\r\n")[-1]
34
35 if data.startswith("TNBU") and buffer.tell() != 0:
36 records.append(buffer.getvalue())
37 buffer.seek(0)
38 buffer.write(data)
39 else:
40 buffer.write(data)
41
42 return records
43
44
45def make_serializer(from_file):
46 with open(from_file) as fp:
47 keystore = { i['mac']: i['x_authkey'] for i in json.load(fp) }
48
49 return InformSerializer("", keystore)
50
51
52if __name__ == "__main__":
53 ser = make_serializer("devices.json")
54
55 for i, data in enumerate(collect_records("mfi.out")):
56 try:
57 packet = ser.parse(StringIO(data))
58 print packet.raw_payload
59 except ValueError:
60 pass
diff --git a/server.py b/server.py
deleted file mode 100644
index 4159736..0000000
--- a/server.py
+++ /dev/null
@@ -1,66 +0,0 @@
1import os
2import subprocess
3import tornado.web
4import tornado.ioloop
5import tornado.options
6import tornado.process
7import tornado.template
8import tornado.httpserver
9from mfiapi import MFiAPI
10from tornado.options import define, options
11
12define("port", default=8888, help="run on the given port", type=int)
13
14
15class PowerStatusHandler(tornado.web.RequestHandler):
16
17 def __init__(self, *args, **kwargs):
18 self.api = MFiAPI('172.16.0.38:6443')
19 super(PowerStatusHandler, self).__init__(*args, **kwargs)
20
21 def get(self):
22 self.api.login('admin', 'password')
23 self.finish(self.api.port_status())
24
25 def post(self):
26 self.api.login('admin', 'password')
27
28 for key, value in self.request.arguments.items():
29 self.api.toggle_port(key)
30
31
32class IndexHandler(tornado.web.RequestHandler):
33
34 def __init__(self, *args, **kwargs):
35 self.api = MFiAPI('172.16.0.38:6443')
36 super(IndexHandler, self).__init__(*args, **kwargs)
37
38 def get(self):
39 self.api.login('admin', 'password')
40
41 ports = [(port, port.replace(" ", "_").replace("'", "-")) for port in self.api.port_status().keys()]
42
43 self.render("index.html", ports=ports)
44
45
46class Application(tornado.web.Application):
47
48 def __init__(self):
49 handlers = [
50 (r"/power-status/?", PowerStatusHandler),
51 (r"/?", IndexHandler),
52 ]
53 settings = dict(
54 template_path=os.path.join(os.path.dirname(__file__), "templates"),
55 static_path=os.path.join(os.path.dirname(__file__), "static"),
56 debug=True,
57 autoescape=None,
58 )
59 tornado.web.Application.__init__(self, handlers, **settings)
60
61
62if __name__ == "__main__":
63 tornado.options.parse_command_line()
64 http_server = tornado.httpserver.HTTPServer(Application())
65 http_server.listen(options.port)
66 tornado.ioloop.IOLoop.instance().start()
diff --git a/static/vendor/images/ajax-loader.gif b/static/vendor/images/ajax-loader.gif
deleted file mode 100644
index fd1a189..0000000
--- a/static/vendor/images/ajax-loader.gif
+++ /dev/null
Binary files differ
diff --git a/static/vendor/images/icons-18-black.png b/static/vendor/images/icons-18-black.png
deleted file mode 100644
index 7916463..0000000
--- a/static/vendor/images/icons-18-black.png
+++ /dev/null
Binary files differ
diff --git a/static/vendor/images/icons-18-white.png b/static/vendor/images/icons-18-white.png
deleted file mode 100644
index 3419b81..0000000
--- a/static/vendor/images/icons-18-white.png
+++ /dev/null
Binary files differ
diff --git a/static/vendor/images/icons-36-black.png b/static/vendor/images/icons-36-black.png
deleted file mode 100644
index 043bfcd..0000000
--- a/static/vendor/images/icons-36-black.png
+++ /dev/null
Binary files differ
diff --git a/static/vendor/images/icons-36-white.png b/static/vendor/images/icons-36-white.png
deleted file mode 100644
index 12455c9..0000000
--- a/static/vendor/images/icons-36-white.png
+++ /dev/null
Binary files differ
diff --git a/static/vendor/jquery-1.10.2.js b/static/vendor/jquery-1.10.2.js
deleted file mode 100644
index c5c6482..0000000
--- a/static/vendor/jquery-1.10.2.js
+++ /dev/null
@@ -1,9789 +0,0 @@
1/*!
2 * jQuery JavaScript Library v1.10.2
3 * http://jquery.com/
4 *
5 * Includes Sizzle.js
6 * http://sizzlejs.com/
7 *
8 * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
9 * Released under the MIT license
10 * http://jquery.org/license
11 *
12 * Date: 2013-07-03T13:48Z
13 */
14(function( window, undefined ) {
15
16// Can't do this because several apps including ASP.NET trace
17// the stack via arguments.caller.callee and Firefox dies if
18// you try to trace through "use strict" call chains. (#13335)
19// Support: Firefox 18+
20//"use strict";
21var
22 // The deferred used on DOM ready
23 readyList,
24
25 // A central reference to the root jQuery(document)
26 rootjQuery,
27
28 // Support: IE<10
29 // For `typeof xmlNode.method` instead of `xmlNode.method !== undefined`
30 core_strundefined = typeof undefined,
31
32 // Use the correct document accordingly with window argument (sandbox)
33 location = window.location,
34 document = window.document,
35 docElem = document.documentElement,
36
37 // Map over jQuery in case of overwrite
38 _jQuery = window.jQuery,
39
40 // Map over the $ in case of overwrite
41 _$ = window.$,
42
43 // [[Class]] -> type pairs
44 class2type = {},
45
46 // List of deleted data cache ids, so we can reuse them
47 core_deletedIds = [],
48
49 core_version = "1.10.2",
50
51 // Save a reference to some core methods
52 core_concat = core_deletedIds.concat,
53 core_push = core_deletedIds.push,
54 core_slice = core_deletedIds.slice,
55 core_indexOf = core_deletedIds.indexOf,
56 core_toString = class2type.toString,
57 core_hasOwn = class2type.hasOwnProperty,
58 core_trim = core_version.trim,
59
60 // Define a local copy of jQuery
61 jQuery = function( selector, context ) {
62 // The jQuery object is actually just the init constructor 'enhanced'
63 return new jQuery.fn.init( selector, context, rootjQuery );
64 },
65
66 // Used for matching numbers
67 core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
68
69 // Used for splitting on whitespace
70 core_rnotwhite = /\S+/g,
71
72 // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
73 rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
74
75 // A simple way to check for HTML strings
76 // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
77 // Strict HTML recognition (#11290: must start with <)
78 rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
79
80 // Match a standalone tag
81 rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
82
83 // JSON RegExp
84 rvalidchars = /^[\],:{}\s]*$/,
85 rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
86 rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
87 rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
88
89 // Matches dashed string for camelizing
90 rmsPrefix = /^-ms-/,
91 rdashAlpha = /-([\da-z])/gi,
92
93 // Used by jQuery.camelCase as callback to replace()
94 fcamelCase = function( all, letter ) {
95 return letter.toUpperCase();
96 },
97
98 // The ready event handler
99 completed = function( event ) {
100
101 // readyState === "complete" is good enough for us to call the dom ready in oldIE
102 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
103 detach();
104 jQuery.ready();
105 }
106 },
107 // Clean-up method for dom ready events
108 detach = function() {
109 if ( document.addEventListener ) {
110 document.removeEventListener( "DOMContentLoaded", completed, false );
111 window.removeEventListener( "load", completed, false );
112
113 } else {
114 document.detachEvent( "onreadystatechange", completed );
115 window.detachEvent( "onload", completed );
116 }
117 };
118
119jQuery.fn = jQuery.prototype = {
120 // The current version of jQuery being used
121 jquery: core_version,
122
123 constructor: jQuery,
124 init: function( selector, context, rootjQuery ) {
125 var match, elem;
126
127 // HANDLE: $(""), $(null), $(undefined), $(false)
128 if ( !selector ) {
129 return this;
130 }
131
132 // Handle HTML strings
133 if ( typeof selector === "string" ) {
134 if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
135 // Assume that strings that start and end with <> are HTML and skip the regex check
136 match = [ null, selector, null ];
137
138 } else {
139 match = rquickExpr.exec( selector );
140 }
141
142 // Match html or make sure no context is specified for #id
143 if ( match && (match[1] || !context) ) {
144
145 // HANDLE: $(html) -> $(array)
146 if ( match[1] ) {
147 context = context instanceof jQuery ? context[0] : context;
148
149 // scripts is true for back-compat
150 jQuery.merge( this, jQuery.parseHTML(
151 match[1],
152 context && context.nodeType ? context.ownerDocument || context : document,
153 true
154 ) );
155
156 // HANDLE: $(html, props)
157 if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
158 for ( match in context ) {
159 // Properties of context are called as methods if possible
160 if ( jQuery.isFunction( this[ match ] ) ) {
161 this[ match ]( context[ match ] );
162
163 // ...and otherwise set as attributes
164 } else {
165 this.attr( match, context[ match ] );
166 }
167 }
168 }
169
170 return this;
171
172 // HANDLE: $(#id)
173 } else {
174 elem = document.getElementById( match[2] );
175
176 // Check parentNode to catch when Blackberry 4.6 returns
177 // nodes that are no longer in the document #6963
178 if ( elem && elem.parentNode ) {
179 // Handle the case where IE and Opera return items
180 // by name instead of ID
181 if ( elem.id !== match[2] ) {
182 return rootjQuery.find( selector );
183 }
184
185 // Otherwise, we inject the element directly into the jQuery object
186 this.length = 1;
187 this[0] = elem;
188 }
189
190 this.context = document;
191 this.selector = selector;
192 return this;
193 }
194
195 // HANDLE: $(expr, $(...))
196 } else if ( !context || context.jquery ) {
197 return ( context || rootjQuery ).find( selector );
198
199 // HANDLE: $(expr, context)
200 // (which is just equivalent to: $(context).find(expr)
201 } else {
202 return this.constructor( context ).find( selector );
203 }
204
205 // HANDLE: $(DOMElement)
206 } else if ( selector.nodeType ) {
207 this.context = this[0] = selector;
208 this.length = 1;
209 return this;
210
211 // HANDLE: $(function)
212 // Shortcut for document ready
213 } else if ( jQuery.isFunction( selector ) ) {
214 return rootjQuery.ready( selector );
215 }
216
217 if ( selector.selector !== undefined ) {
218 this.selector = selector.selector;
219 this.context = selector.context;
220 }
221
222 return jQuery.makeArray( selector, this );
223 },
224
225 // Start with an empty selector
226 selector: "",
227
228 // The default length of a jQuery object is 0
229 length: 0,
230
231 toArray: function() {
232 return core_slice.call( this );
233 },
234
235 // Get the Nth element in the matched element set OR
236 // Get the whole matched element set as a clean array
237 get: function( num ) {
238 return num == null ?
239
240 // Return a 'clean' array
241 this.toArray() :
242
243 // Return just the object
244 ( num < 0 ? this[ this.length + num ] : this[ num ] );
245 },
246
247 // Take an array of elements and push it onto the stack
248 // (returning the new matched element set)
249 pushStack: function( elems ) {
250
251 // Build a new jQuery matched element set
252 var ret = jQuery.merge( this.constructor(), elems );
253
254 // Add the old object onto the stack (as a reference)
255 ret.prevObject = this;
256 ret.context = this.context;
257
258 // Return the newly-formed element set
259 return ret;
260 },
261
262 // Execute a callback for every element in the matched set.
263 // (You can seed the arguments with an array of args, but this is
264 // only used internally.)
265 each: function( callback, args ) {
266 return jQuery.each( this, callback, args );
267 },
268
269 ready: function( fn ) {
270 // Add the callback
271 jQuery.ready.promise().done( fn );
272
273 return this;
274 },
275
276 slice: function() {
277 return this.pushStack( core_slice.apply( this, arguments ) );
278 },
279
280 first: function() {
281 return this.eq( 0 );
282 },
283
284 last: function() {
285 return this.eq( -1 );
286 },
287
288 eq: function( i ) {
289 var len = this.length,
290 j = +i + ( i < 0 ? len : 0 );
291 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
292 },
293
294 map: function( callback ) {
295 return this.pushStack( jQuery.map(this, function( elem, i ) {
296 return callback.call( elem, i, elem );
297 }));
298 },
299
300 end: function() {
301 return this.prevObject || this.constructor(null);
302 },
303
304 // For internal use only.
305 // Behaves like an Array's method, not like a jQuery method.
306 push: core_push,
307 sort: [].sort,
308 splice: [].splice
309};
310
311// Give the init function the jQuery prototype for later instantiation
312jQuery.fn.init.prototype = jQuery.fn;
313
314jQuery.extend = jQuery.fn.extend = function() {
315 var src, copyIsArray, copy, name, options, clone,
316 target = arguments[0] || {},
317 i = 1,
318 length = arguments.length,
319 deep = false;
320
321 // Handle a deep copy situation
322 if ( typeof target === "boolean" ) {
323 deep = target;
324 target = arguments[1] || {};
325 // skip the boolean and the target
326 i = 2;
327 }
328
329 // Handle case when target is a string or something (possible in deep copy)
330 if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
331 target = {};
332 }
333
334 // extend jQuery itself if only one argument is passed
335 if ( length === i ) {
336 target = this;
337 --i;
338 }
339
340 for ( ; i < length; i++ ) {
341 // Only deal with non-null/undefined values
342 if ( (options = arguments[ i ]) != null ) {
343 // Extend the base object
344 for ( name in options ) {
345 src = target[ name ];
346 copy = options[ name ];
347
348 // Prevent never-ending loop
349 if ( target === copy ) {
350 continue;
351 }
352
353 // Recurse if we're merging plain objects or arrays
354 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
355 if ( copyIsArray ) {
356 copyIsArray = false;
357 clone = src && jQuery.isArray(src) ? src : [];
358
359 } else {
360 clone = src && jQuery.isPlainObject(src) ? src : {};
361 }
362
363 // Never move original objects, clone them
364 target[ name ] = jQuery.extend( deep, clone, copy );
365
366 // Don't bring in undefined values
367 } else if ( copy !== undefined ) {
368 target[ name ] = copy;
369 }
370 }
371 }
372 }
373
374 // Return the modified object
375 return target;
376};
377
378jQuery.extend({
379 // Unique for each copy of jQuery on the page
380 // Non-digits removed to match rinlinejQuery
381 expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
382
383 noConflict: function( deep ) {
384 if ( window.$ === jQuery ) {
385 window.$ = _$;
386 }
387
388 if ( deep && window.jQuery === jQuery ) {
389 window.jQuery = _jQuery;
390 }
391
392 return jQuery;
393 },
394
395 // Is the DOM ready to be used? Set to true once it occurs.
396 isReady: false,
397
398 // A counter to track how many items to wait for before
399 // the ready event fires. See #6781
400 readyWait: 1,
401
402 // Hold (or release) the ready event
403 holdReady: function( hold ) {
404 if ( hold ) {
405 jQuery.readyWait++;
406 } else {
407 jQuery.ready( true );
408 }
409 },
410
411 // Handle when the DOM is ready
412 ready: function( wait ) {
413
414 // Abort if there are pending holds or we're already ready
415 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
416 return;
417 }
418
419 // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
420 if ( !document.body ) {
421 return setTimeout( jQuery.ready );
422 }
423
424 // Remember that the DOM is ready
425 jQuery.isReady = true;
426
427 // If a normal DOM Ready event fired, decrement, and wait if need be
428 if ( wait !== true && --jQuery.readyWait > 0 ) {
429 return;
430 }
431
432 // If there are functions bound, to execute
433 readyList.resolveWith( document, [ jQuery ] );
434
435 // Trigger any bound ready events
436 if ( jQuery.fn.trigger ) {
437 jQuery( document ).trigger("ready").off("ready");
438 }
439 },
440
441 // See test/unit/core.js for details concerning isFunction.
442 // Since version 1.3, DOM methods and functions like alert
443 // aren't supported. They return false on IE (#2968).
444 isFunction: function( obj ) {
445 return jQuery.type(obj) === "function";
446 },
447
448 isArray: Array.isArray || function( obj ) {
449 return jQuery.type(obj) === "array";
450 },
451
452 isWindow: function( obj ) {
453 /* jshint eqeqeq: false */
454 return obj != null && obj == obj.window;
455 },
456
457 isNumeric: function( obj ) {
458 return !isNaN( parseFloat(obj) ) && isFinite( obj );
459 },
460
461 type: function( obj ) {
462 if ( obj == null ) {
463 return String( obj );
464 }
465 return typeof obj === "object" || typeof obj === "function" ?
466 class2type[ core_toString.call(obj) ] || "object" :
467 typeof obj;
468 },
469
470 isPlainObject: function( obj ) {
471 var key;
472
473 // Must be an Object.
474 // Because of IE, we also have to check the presence of the constructor property.
475 // Make sure that DOM nodes and window objects don't pass through, as well
476 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
477 return false;
478 }
479
480 try {
481 // Not own constructor property must be Object
482 if ( obj.constructor &&
483 !core_hasOwn.call(obj, "constructor") &&
484 !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
485 return false;
486 }
487 } catch ( e ) {
488 // IE8,9 Will throw exceptions on certain host objects #9897
489 return false;
490 }
491
492 // Support: IE<9
493 // Handle iteration over inherited properties before own properties.
494 if ( jQuery.support.ownLast ) {
495 for ( key in obj ) {
496 return core_hasOwn.call( obj, key );
497 }
498 }
499
500 // Own properties are enumerated firstly, so to speed up,
501 // if last one is own, then all properties are own.
502 for ( key in obj ) {}
503
504 return key === undefined || core_hasOwn.call( obj, key );
505 },
506
507 isEmptyObject: function( obj ) {
508 var name;
509 for ( name in obj ) {
510 return false;
511 }
512 return true;
513 },
514
515 error: function( msg ) {
516 throw new Error( msg );
517 },
518
519 // data: string of html
520 // context (optional): If specified, the fragment will be created in this context, defaults to document
521 // keepScripts (optional): If true, will include scripts passed in the html string
522 parseHTML: function( data, context, keepScripts ) {
523 if ( !data || typeof data !== "string" ) {
524 return null;
525 }
526 if ( typeof context === "boolean" ) {
527 keepScripts = context;
528 context = false;
529 }
530 context = context || document;
531
532 var parsed = rsingleTag.exec( data ),
533 scripts = !keepScripts && [];
534
535 // Single tag
536 if ( parsed ) {
537 return [ context.createElement( parsed[1] ) ];
538 }
539
540 parsed = jQuery.buildFragment( [ data ], context, scripts );
541 if ( scripts ) {
542 jQuery( scripts ).remove();
543 }
544 return jQuery.merge( [], parsed.childNodes );
545 },
546
547 parseJSON: function( data ) {
548 // Attempt to parse using the native JSON parser first
549 if ( window.JSON && window.JSON.parse ) {
550 return window.JSON.parse( data );
551 }
552
553 if ( data === null ) {
554 return data;
555 }
556
557 if ( typeof data === "string" ) {
558
559 // Make sure leading/trailing whitespace is removed (IE can't handle it)
560 data = jQuery.trim( data );
561
562 if ( data ) {
563 // Make sure the incoming data is actual JSON
564 // Logic borrowed from http://json.org/json2.js
565 if ( rvalidchars.test( data.replace( rvalidescape, "@" )
566 .replace( rvalidtokens, "]" )
567 .replace( rvalidbraces, "")) ) {
568
569 return ( new Function( "return " + data ) )();
570 }
571 }
572 }
573
574 jQuery.error( "Invalid JSON: " + data );
575 },
576
577 // Cross-browser xml parsing
578 parseXML: function( data ) {
579 var xml, tmp;
580 if ( !data || typeof data !== "string" ) {
581 return null;
582 }
583 try {
584 if ( window.DOMParser ) { // Standard
585 tmp = new DOMParser();
586 xml = tmp.parseFromString( data , "text/xml" );
587 } else { // IE
588 xml = new ActiveXObject( "Microsoft.XMLDOM" );
589 xml.async = "false";
590 xml.loadXML( data );
591 }
592 } catch( e ) {
593 xml = undefined;
594 }
595 if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
596 jQuery.error( "Invalid XML: " + data );
597 }
598 return xml;
599 },
600
601 noop: function() {},
602
603 // Evaluates a script in a global context
604 // Workarounds based on findings by Jim Driscoll
605 // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
606 globalEval: function( data ) {
607 if ( data && jQuery.trim( data ) ) {
608 // We use execScript on Internet Explorer
609 // We use an anonymous function so that context is window
610 // rather than jQuery in Firefox
611 ( window.execScript || function( data ) {
612 window[ "eval" ].call( window, data );
613 } )( data );
614 }
615 },
616
617 // Convert dashed to camelCase; used by the css and data modules
618 // Microsoft forgot to hump their vendor prefix (#9572)
619 camelCase: function( string ) {
620 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
621 },
622
623 nodeName: function( elem, name ) {
624 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
625 },
626
627 // args is for internal usage only
628 each: function( obj, callback, args ) {
629 var value,
630 i = 0,
631 length = obj.length,
632 isArray = isArraylike( obj );
633
634 if ( args ) {
635 if ( isArray ) {
636 for ( ; i < length; i++ ) {
637 value = callback.apply( obj[ i ], args );
638
639 if ( value === false ) {
640 break;
641 }
642 }
643 } else {
644 for ( i in obj ) {
645 value = callback.apply( obj[ i ], args );
646
647 if ( value === false ) {
648 break;
649 }
650 }
651 }
652
653 // A special, fast, case for the most common use of each
654 } else {
655 if ( isArray ) {
656 for ( ; i < length; i++ ) {
657 value = callback.call( obj[ i ], i, obj[ i ] );
658
659 if ( value === false ) {
660 break;
661 }
662 }
663 } else {
664 for ( i in obj ) {
665 value = callback.call( obj[ i ], i, obj[ i ] );
666
667 if ( value === false ) {
668 break;
669 }
670 }
671 }
672 }
673
674 return obj;
675 },
676
677 // Use native String.trim function wherever possible
678 trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
679 function( text ) {
680 return text == null ?
681 "" :
682 core_trim.call( text );
683 } :
684
685 // Otherwise use our own trimming functionality
686 function( text ) {
687 return text == null ?
688 "" :
689 ( text + "" ).replace( rtrim, "" );
690 },
691
692 // results is for internal usage only
693 makeArray: function( arr, results ) {
694 var ret = results || [];
695
696 if ( arr != null ) {
697 if ( isArraylike( Object(arr) ) ) {
698 jQuery.merge( ret,
699 typeof arr === "string" ?
700 [ arr ] : arr
701 );
702 } else {
703 core_push.call( ret, arr );
704 }
705 }
706
707 return ret;
708 },
709
710 inArray: function( elem, arr, i ) {
711 var len;
712
713 if ( arr ) {
714 if ( core_indexOf ) {
715 return core_indexOf.call( arr, elem, i );
716 }
717
718 len = arr.length;
719 i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
720
721 for ( ; i < len; i++ ) {
722 // Skip accessing in sparse arrays
723 if ( i in arr && arr[ i ] === elem ) {
724 return i;
725 }
726 }
727 }
728
729 return -1;
730 },
731
732 merge: function( first, second ) {
733 var l = second.length,
734 i = first.length,
735 j = 0;
736
737 if ( typeof l === "number" ) {
738 for ( ; j < l; j++ ) {
739 first[ i++ ] = second[ j ];
740 }
741 } else {
742 while ( second[j] !== undefined ) {
743 first[ i++ ] = second[ j++ ];
744 }
745 }
746
747 first.length = i;
748
749 return first;
750 },
751
752 grep: function( elems, callback, inv ) {
753 var retVal,
754 ret = [],
755 i = 0,
756 length = elems.length;
757 inv = !!inv;
758
759 // Go through the array, only saving the items
760 // that pass the validator function
761 for ( ; i < length; i++ ) {
762 retVal = !!callback( elems[ i ], i );
763 if ( inv !== retVal ) {
764 ret.push( elems[ i ] );
765 }
766 }
767
768 return ret;
769 },
770
771 // arg is for internal usage only
772 map: function( elems, callback, arg ) {
773 var value,
774 i = 0,
775 length = elems.length,
776 isArray = isArraylike( elems ),
777 ret = [];
778
779 // Go through the array, translating each of the items to their
780 if ( isArray ) {
781 for ( ; i < length; i++ ) {
782 value = callback( elems[ i ], i, arg );
783
784 if ( value != null ) {
785 ret[ ret.length ] = value;
786 }
787 }
788
789 // Go through every key on the object,
790 } else {
791 for ( i in elems ) {
792 value = callback( elems[ i ], i, arg );
793
794 if ( value != null ) {
795 ret[ ret.length ] = value;
796 }
797 }
798 }
799
800 // Flatten any nested arrays
801 return core_concat.apply( [], ret );
802 },
803
804 // A global GUID counter for objects
805 guid: 1,
806
807 // Bind a function to a context, optionally partially applying any
808 // arguments.
809 proxy: function( fn, context ) {
810 var args, proxy, tmp;
811
812 if ( typeof context === "string" ) {
813 tmp = fn[ context ];
814 context = fn;
815 fn = tmp;
816 }
817
818 // Quick check to determine if target is callable, in the spec
819 // this throws a TypeError, but we will just return undefined.
820 if ( !jQuery.isFunction( fn ) ) {
821 return undefined;
822 }
823
824 // Simulated bind
825 args = core_slice.call( arguments, 2 );
826 proxy = function() {
827 return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
828 };
829
830 // Set the guid of unique handler to the same of original handler, so it can be removed
831 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
832
833 return proxy;
834 },
835
836 // Multifunctional method to get and set values of a collection
837 // The value/s can optionally be executed if it's a function
838 access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
839 var i = 0,
840 length = elems.length,
841 bulk = key == null;
842
843 // Sets many values
844 if ( jQuery.type( key ) === "object" ) {
845 chainable = true;
846 for ( i in key ) {
847 jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
848 }
849
850 // Sets one value
851 } else if ( value !== undefined ) {
852 chainable = true;
853
854 if ( !jQuery.isFunction( value ) ) {
855 raw = true;
856 }
857
858 if ( bulk ) {
859 // Bulk operations run against the entire set
860 if ( raw ) {
861 fn.call( elems, value );
862 fn = null;
863
864 // ...except when executing function values
865 } else {
866 bulk = fn;
867 fn = function( elem, key, value ) {
868 return bulk.call( jQuery( elem ), value );
869 };
870 }
871 }
872
873 if ( fn ) {
874 for ( ; i < length; i++ ) {
875 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
876 }
877 }
878 }
879
880 return chainable ?
881 elems :
882
883 // Gets
884 bulk ?
885 fn.call( elems ) :
886 length ? fn( elems[0], key ) : emptyGet;
887 },
888
889 now: function() {
890 return ( new Date() ).getTime();
891 },
892
893 // A method for quickly swapping in/out CSS properties to get correct calculations.
894 // Note: this method belongs to the css module but it's needed here for the support module.
895 // If support gets modularized, this method should be moved back to the css module.
896 swap: function( elem, options, callback, args ) {
897 var ret, name,
898 old = {};
899
900 // Remember the old values, and insert the new ones
901 for ( name in options ) {
902 old[ name ] = elem.style[ name ];
903 elem.style[ name ] = options[ name ];
904 }
905
906 ret = callback.apply( elem, args || [] );
907
908 // Revert the old values
909 for ( name in options ) {
910 elem.style[ name ] = old[ name ];
911 }
912
913 return ret;
914 }
915});
916
917jQuery.ready.promise = function( obj ) {
918 if ( !readyList ) {
919
920 readyList = jQuery.Deferred();
921
922 // Catch cases where $(document).ready() is called after the browser event has already occurred.
923 // we once tried to use readyState "interactive" here, but it caused issues like the one
924 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
925 if ( document.readyState === "complete" ) {
926 // Handle it asynchronously to allow scripts the opportunity to delay ready
927 setTimeout( jQuery.ready );
928
929 // Standards-based browsers support DOMContentLoaded
930 } else if ( document.addEventListener ) {
931 // Use the handy event callback
932 document.addEventListener( "DOMContentLoaded", completed, false );
933
934 // A fallback to window.onload, that will always work
935 window.addEventListener( "load", completed, false );
936
937 // If IE event model is used
938 } else {
939 // Ensure firing before onload, maybe late but safe also for iframes
940 document.attachEvent( "onreadystatechange", completed );
941
942 // A fallback to window.onload, that will always work
943 window.attachEvent( "onload", completed );
944
945 // If IE and not a frame
946 // continually check to see if the document is ready
947 var top = false;
948
949 try {
950 top = window.frameElement == null && document.documentElement;
951 } catch(e) {}
952
953 if ( top && top.doScroll ) {
954 (function doScrollCheck() {
955 if ( !jQuery.isReady ) {
956
957 try {
958 // Use the trick by Diego Perini
959 // http://javascript.nwbox.com/IEContentLoaded/
960 top.doScroll("left");
961 } catch(e) {
962 return setTimeout( doScrollCheck, 50 );
963 }
964
965 // detach all dom ready events
966 detach();
967
968 // and execute any waiting functions
969 jQuery.ready();
970 }
971 })();
972 }
973 }
974 }
975 return readyList.promise( obj );
976};
977
978// Populate the class2type map
979jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
980 class2type[ "[object " + name + "]" ] = name.toLowerCase();
981});
982
983function isArraylike( obj ) {
984 var length = obj.length,
985 type = jQuery.type( obj );
986
987 if ( jQuery.isWindow( obj ) ) {
988 return false;
989 }
990
991 if ( obj.nodeType === 1 && length ) {
992 return true;
993 }
994
995 return type === "array" || type !== "function" &&
996 ( length === 0 ||
997 typeof length === "number" && length > 0 && ( length - 1 ) in obj );
998}
999
1000// All jQuery objects should point back to these
1001rootjQuery = jQuery(document);
1002/*!
1003 * Sizzle CSS Selector Engine v1.10.2
1004 * http://sizzlejs.com/
1005 *
1006 * Copyright 2013 jQuery Foundation, Inc. and other contributors
1007 * Released under the MIT license
1008 * http://jquery.org/license
1009 *
1010 * Date: 2013-07-03
1011 */
1012(function( window, undefined ) {
1013
1014var i,
1015 support,
1016 cachedruns,
1017 Expr,
1018 getText,
1019 isXML,
1020 compile,
1021 outermostContext,
1022 sortInput,
1023
1024 // Local document vars
1025 setDocument,
1026 document,
1027 docElem,
1028 documentIsHTML,
1029 rbuggyQSA,
1030 rbuggyMatches,
1031 matches,
1032 contains,
1033
1034 // Instance-specific data
1035 expando = "sizzle" + -(new Date()),
1036 preferredDoc = window.document,
1037 dirruns = 0,
1038 done = 0,
1039 classCache = createCache(),
1040 tokenCache = createCache(),
1041 compilerCache = createCache(),
1042 hasDuplicate = false,
1043 sortOrder = function( a, b ) {
1044 if ( a === b ) {
1045 hasDuplicate = true;
1046 return 0;
1047 }
1048 return 0;
1049 },
1050
1051 // General-purpose constants
1052 strundefined = typeof undefined,
1053 MAX_NEGATIVE = 1 << 31,
1054
1055 // Instance methods
1056 hasOwn = ({}).hasOwnProperty,
1057 arr = [],
1058 pop = arr.pop,
1059 push_native = arr.push,
1060 push = arr.push,
1061 slice = arr.slice,
1062 // Use a stripped-down indexOf if we can't use a native one
1063 indexOf = arr.indexOf || function( elem ) {
1064 var i = 0,
1065 len = this.length;
1066 for ( ; i < len; i++ ) {
1067 if ( this[i] === elem ) {
1068 return i;
1069 }
1070 }
1071 return -1;
1072 },
1073
1074 booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
1075
1076 // Regular expressions
1077
1078 // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
1079 whitespace = "[\\x20\\t\\r\\n\\f]",
1080 // http://www.w3.org/TR/css3-syntax/#characters
1081 characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
1082
1083 // Loosely modeled on CSS identifier characters
1084 // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
1085 // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
1086 identifier = characterEncoding.replace( "w", "w#" ),
1087
1088 // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
1089 attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
1090 "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
1091
1092 // Prefer arguments quoted,
1093 // then not containing pseudos/brackets,
1094 // then attribute selectors/non-parenthetical expressions,
1095 // then anything else
1096 // These preferences are here to reduce the number of selectors
1097 // needing tokenize in the PSEUDO preFilter
1098 pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
1099
1100 // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
1101 rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
1102
1103 rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
1104 rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
1105
1106 rsibling = new RegExp( whitespace + "*[+~]" ),
1107 rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*)" + whitespace + "*\\]", "g" ),
1108
1109 rpseudo = new RegExp( pseudos ),
1110 ridentifier = new RegExp( "^" + identifier + "$" ),
1111
1112 matchExpr = {
1113 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
1114 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
1115 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
1116 "ATTR": new RegExp( "^" + attributes ),
1117 "PSEUDO": new RegExp( "^" + pseudos ),
1118 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
1119 "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
1120 "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
1121 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
1122 // For use in libraries implementing .is()
1123 // We use this for POS matching in `select`
1124 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
1125 whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
1126 },
1127
1128 rnative = /^[^{]+\{\s*\[native \w/,
1129
1130 // Easily-parseable/retrievable ID or TAG or CLASS selectors
1131 rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
1132
1133 rinputs = /^(?:input|select|textarea|button)$/i,
1134 rheader = /^h\d$/i,
1135
1136 rescape = /'|\\/g,
1137
1138 // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
1139 runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
1140 funescape = function( _, escaped, escapedWhitespace ) {
1141 var high = "0x" + escaped - 0x10000;
1142 // NaN means non-codepoint
1143 // Support: Firefox
1144 // Workaround erroneous numeric interpretation of +"0x"
1145 return high !== high || escapedWhitespace ?
1146 escaped :
1147 // BMP codepoint
1148 high < 0 ?
1149 String.fromCharCode( high + 0x10000 ) :
1150 // Supplemental Plane codepoint (surrogate pair)
1151 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
1152 };
1153
1154// Optimize for push.apply( _, NodeList )
1155try {
1156 push.apply(
1157 (arr = slice.call( preferredDoc.childNodes )),
1158 preferredDoc.childNodes
1159 );
1160 // Support: Android<4.0
1161 // Detect silently failing push.apply
1162 arr[ preferredDoc.childNodes.length ].nodeType;
1163} catch ( e ) {
1164 push = { apply: arr.length ?
1165
1166 // Leverage slice if possible
1167 function( target, els ) {
1168 push_native.apply( target, slice.call(els) );
1169 } :
1170
1171 // Support: IE<9
1172 // Otherwise append directly
1173 function( target, els ) {
1174 var j = target.length,
1175 i = 0;
1176 // Can't trust NodeList.length
1177 while ( (target[j++] = els[i++]) ) {}
1178 target.length = j - 1;
1179 }
1180 };
1181}
1182
1183function Sizzle( selector, context, results, seed ) {
1184 var match, elem, m, nodeType,
1185 // QSA vars
1186 i, groups, old, nid, newContext, newSelector;
1187
1188 if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
1189 setDocument( context );
1190 }
1191
1192 context = context || document;
1193 results = results || [];
1194
1195 if ( !selector || typeof selector !== "string" ) {
1196 return results;
1197 }
1198
1199 if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
1200 return [];
1201 }
1202
1203 if ( documentIsHTML && !seed ) {
1204
1205 // Shortcuts
1206 if ( (match = rquickExpr.exec( selector )) ) {
1207 // Speed-up: Sizzle("#ID")
1208 if ( (m = match[1]) ) {
1209 if ( nodeType === 9 ) {
1210 elem = context.getElementById( m );
1211 // Check parentNode to catch when Blackberry 4.6 returns
1212 // nodes that are no longer in the document #6963
1213 if ( elem && elem.parentNode ) {
1214 // Handle the case where IE, Opera, and Webkit return items
1215 // by name instead of ID
1216 if ( elem.id === m ) {
1217 results.push( elem );
1218 return results;
1219 }
1220 } else {
1221 return results;
1222 }
1223 } else {
1224 // Context is not a document
1225 if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
1226 contains( context, elem ) && elem.id === m ) {
1227 results.push( elem );
1228 return results;
1229 }
1230 }
1231
1232 // Speed-up: Sizzle("TAG")
1233 } else if ( match[2] ) {
1234 push.apply( results, context.getElementsByTagName( selector ) );
1235 return results;
1236
1237 // Speed-up: Sizzle(".CLASS")
1238 } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
1239 push.apply( results, context.getElementsByClassName( m ) );
1240 return results;
1241 }
1242 }
1243
1244 // QSA path
1245 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
1246 nid = old = expando;
1247 newContext = context;
1248 newSelector = nodeType === 9 && selector;
1249
1250 // qSA works strangely on Element-rooted queries
1251 // We can work around this by specifying an extra ID on the root
1252 // and working up from there (Thanks to Andrew Dupont for the technique)
1253 // IE 8 doesn't work on object elements
1254 if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
1255 groups = tokenize( selector );
1256
1257 if ( (old = context.getAttribute("id")) ) {
1258 nid = old.replace( rescape, "\\$&" );
1259 } else {
1260 context.setAttribute( "id", nid );
1261 }
1262 nid = "[id='" + nid + "'] ";
1263
1264 i = groups.length;
1265 while ( i-- ) {
1266 groups[i] = nid + toSelector( groups[i] );
1267 }
1268 newContext = rsibling.test( selector ) && context.parentNode || context;
1269 newSelector = groups.join(",");
1270 }
1271
1272 if ( newSelector ) {
1273 try {
1274 push.apply( results,
1275 newContext.querySelectorAll( newSelector )
1276 );
1277 return results;
1278 } catch(qsaError) {
1279 } finally {
1280 if ( !old ) {
1281 context.removeAttribute("id");
1282 }
1283 }
1284 }
1285 }
1286 }
1287
1288 // All others
1289 return select( selector.replace( rtrim, "$1" ), context, results, seed );
1290}
1291
1292/**
1293 * Create key-value caches of limited size
1294 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
1295 * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
1296 * deleting the oldest entry
1297 */
1298function createCache() {
1299 var keys = [];
1300
1301 function cache( key, value ) {
1302 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
1303 if ( keys.push( key += " " ) > Expr.cacheLength ) {
1304 // Only keep the most recent entries
1305 delete cache[ keys.shift() ];
1306 }
1307 return (cache[ key ] = value);
1308 }
1309 return cache;
1310}
1311
1312/**
1313 * Mark a function for special use by Sizzle
1314 * @param {Function} fn The function to mark
1315 */
1316function markFunction( fn ) {
1317 fn[ expando ] = true;
1318 return fn;
1319}
1320
1321/**
1322 * Support testing using an element
1323 * @param {Function} fn Passed the created div and expects a boolean result
1324 */
1325function assert( fn ) {
1326 var div = document.createElement("div");
1327
1328 try {
1329 return !!fn( div );
1330 } catch (e) {
1331 return false;
1332 } finally {
1333 // Remove from its parent by default
1334 if ( div.parentNode ) {
1335 div.parentNode.removeChild( div );
1336 }
1337 // release memory in IE
1338 div = null;
1339 }
1340}
1341
1342/**
1343 * Adds the same handler for all of the specified attrs
1344 * @param {String} attrs Pipe-separated list of attributes
1345 * @param {Function} handler The method that will be applied
1346 */
1347function addHandle( attrs, handler ) {
1348 var arr = attrs.split("|"),
1349 i = attrs.length;
1350
1351 while ( i-- ) {
1352 Expr.attrHandle[ arr[i] ] = handler;
1353 }
1354}
1355
1356/**
1357 * Checks document order of two siblings
1358 * @param {Element} a
1359 * @param {Element} b
1360 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
1361 */
1362function siblingCheck( a, b ) {
1363 var cur = b && a,
1364 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
1365 ( ~b.sourceIndex || MAX_NEGATIVE ) -
1366 ( ~a.sourceIndex || MAX_NEGATIVE );
1367
1368 // Use IE sourceIndex if available on both nodes
1369 if ( diff ) {
1370 return diff;
1371 }
1372
1373 // Check if b follows a
1374 if ( cur ) {
1375 while ( (cur = cur.nextSibling) ) {
1376 if ( cur === b ) {
1377 return -1;
1378 }
1379 }
1380 }
1381
1382 return a ? 1 : -1;
1383}
1384
1385/**
1386 * Returns a function to use in pseudos for input types
1387 * @param {String} type
1388 */
1389function createInputPseudo( type ) {
1390 return function( elem ) {
1391 var name = elem.nodeName.toLowerCase();
1392 return name === "input" && elem.type === type;
1393 };
1394}
1395
1396/**
1397 * Returns a function to use in pseudos for buttons
1398 * @param {String} type
1399 */
1400function createButtonPseudo( type ) {
1401 return function( elem ) {
1402 var name = elem.nodeName.toLowerCase();
1403 return (name === "input" || name === "button") && elem.type === type;
1404 };
1405}
1406
1407/**
1408 * Returns a function to use in pseudos for positionals
1409 * @param {Function} fn
1410 */
1411function createPositionalPseudo( fn ) {
1412 return markFunction(function( argument ) {
1413 argument = +argument;
1414 return markFunction(function( seed, matches ) {
1415 var j,
1416 matchIndexes = fn( [], seed.length, argument ),
1417 i = matchIndexes.length;
1418
1419 // Match elements found at the specified indexes
1420 while ( i-- ) {
1421 if ( seed[ (j = matchIndexes[i]) ] ) {
1422 seed[j] = !(matches[j] = seed[j]);
1423 }
1424 }
1425 });
1426 });
1427}
1428
1429/**
1430 * Detect xml
1431 * @param {Element|Object} elem An element or a document
1432 */
1433isXML = Sizzle.isXML = function( elem ) {
1434 // documentElement is verified for cases where it doesn't yet exist
1435 // (such as loading iframes in IE - #4833)
1436 var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1437 return documentElement ? documentElement.nodeName !== "HTML" : false;
1438};
1439
1440// Expose support vars for convenience
1441support = Sizzle.support = {};
1442
1443/**
1444 * Sets document-related variables once based on the current document
1445 * @param {Element|Object} [doc] An element or document object to use to set the document
1446 * @returns {Object} Returns the current document
1447 */
1448setDocument = Sizzle.setDocument = function( node ) {
1449 var doc = node ? node.ownerDocument || node : preferredDoc,
1450 parent = doc.defaultView;
1451
1452 // If no document and documentElement is available, return
1453 if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1454 return document;
1455 }
1456
1457 // Set our document
1458 document = doc;
1459 docElem = doc.documentElement;
1460
1461 // Support tests
1462 documentIsHTML = !isXML( doc );
1463
1464 // Support: IE>8
1465 // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1466 // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1467 // IE6-8 do not support the defaultView property so parent will be undefined
1468 if ( parent && parent.attachEvent && parent !== parent.top ) {
1469 parent.attachEvent( "onbeforeunload", function() {
1470 setDocument();
1471 });
1472 }
1473
1474 /* Attributes
1475 ---------------------------------------------------------------------- */
1476
1477 // Support: IE<8
1478 // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1479 support.attributes = assert(function( div ) {
1480 div.className = "i";
1481 return !div.getAttribute("className");
1482 });
1483
1484 /* getElement(s)By*
1485 ---------------------------------------------------------------------- */
1486
1487 // Check if getElementsByTagName("*") returns only elements
1488 support.getElementsByTagName = assert(function( div ) {
1489 div.appendChild( doc.createComment("") );
1490 return !div.getElementsByTagName("*").length;
1491 });
1492
1493 // Check if getElementsByClassName can be trusted
1494 support.getElementsByClassName = assert(function( div ) {
1495 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1496
1497 // Support: Safari<4
1498 // Catch class over-caching
1499 div.firstChild.className = "i";
1500 // Support: Opera<10
1501 // Catch gEBCN failure to find non-leading classes
1502 return div.getElementsByClassName("i").length === 2;
1503 });
1504
1505 // Support: IE<10
1506 // Check if getElementById returns elements by name
1507 // The broken getElementById methods don't pick up programatically-set names,
1508 // so use a roundabout getElementsByName test
1509 support.getById = assert(function( div ) {
1510 docElem.appendChild( div ).id = expando;
1511 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1512 });
1513
1514 // ID find and filter
1515 if ( support.getById ) {
1516 Expr.find["ID"] = function( id, context ) {
1517 if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1518 var m = context.getElementById( id );
1519 // Check parentNode to catch when Blackberry 4.6 returns
1520 // nodes that are no longer in the document #6963
1521 return m && m.parentNode ? [m] : [];
1522 }
1523 };
1524 Expr.filter["ID"] = function( id ) {
1525 var attrId = id.replace( runescape, funescape );
1526 return function( elem ) {
1527 return elem.getAttribute("id") === attrId;
1528 };
1529 };
1530 } else {
1531 // Support: IE6/7
1532 // getElementById is not reliable as a find shortcut
1533 delete Expr.find["ID"];
1534
1535 Expr.filter["ID"] = function( id ) {
1536 var attrId = id.replace( runescape, funescape );
1537 return function( elem ) {
1538 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1539 return node && node.value === attrId;
1540 };
1541 };
1542 }
1543
1544 // Tag
1545 Expr.find["TAG"] = support.getElementsByTagName ?
1546 function( tag, context ) {
1547 if ( typeof context.getElementsByTagName !== strundefined ) {
1548 return context.getElementsByTagName( tag );
1549 }
1550 } :
1551 function( tag, context ) {
1552 var elem,
1553 tmp = [],
1554 i = 0,
1555 results = context.getElementsByTagName( tag );
1556
1557 // Filter out possible comments
1558 if ( tag === "*" ) {
1559 while ( (elem = results[i++]) ) {
1560 if ( elem.nodeType === 1 ) {
1561 tmp.push( elem );
1562 }
1563 }
1564
1565 return tmp;
1566 }
1567 return results;
1568 };
1569
1570 // Class
1571 Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1572 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1573 return context.getElementsByClassName( className );
1574 }
1575 };
1576
1577 /* QSA/matchesSelector
1578 ---------------------------------------------------------------------- */
1579
1580 // QSA and matchesSelector support
1581
1582 // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1583 rbuggyMatches = [];
1584
1585 // qSa(:focus) reports false when true (Chrome 21)
1586 // We allow this because of a bug in IE8/9 that throws an error
1587 // whenever `document.activeElement` is accessed on an iframe
1588 // So, we allow :focus to pass through QSA all the time to avoid the IE error
1589 // See http://bugs.jquery.com/ticket/13378
1590 rbuggyQSA = [];
1591
1592 if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1593 // Build QSA regex
1594 // Regex strategy adopted from Diego Perini
1595 assert(function( div ) {
1596 // Select is set to empty string on purpose
1597 // This is to test IE's treatment of not explicitly
1598 // setting a boolean content attribute,
1599 // since its presence should be enough
1600 // http://bugs.jquery.com/ticket/12359
1601 div.innerHTML = "<select><option selected=''></option></select>";
1602
1603 // Support: IE8
1604 // Boolean attributes and "value" are not treated correctly
1605 if ( !div.querySelectorAll("[selected]").length ) {
1606 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1607 }
1608
1609 // Webkit/Opera - :checked should return selected option elements
1610 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1611 // IE8 throws error here and will not see later tests
1612 if ( !div.querySelectorAll(":checked").length ) {
1613 rbuggyQSA.push(":checked");
1614 }
1615 });
1616
1617 assert(function( div ) {
1618
1619 // Support: Opera 10-12/IE8
1620 // ^= $= *= and empty values
1621 // Should not select anything
1622 // Support: Windows 8 Native Apps
1623 // The type attribute is restricted during .innerHTML assignment
1624 var input = doc.createElement("input");
1625 input.setAttribute( "type", "hidden" );
1626 div.appendChild( input ).setAttribute( "t", "" );
1627
1628 if ( div.querySelectorAll("[t^='']").length ) {
1629 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1630 }
1631
1632 // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1633 // IE8 throws error here and will not see later tests
1634 if ( !div.querySelectorAll(":enabled").length ) {
1635 rbuggyQSA.push( ":enabled", ":disabled" );
1636 }
1637
1638 // Opera 10-11 does not throw on post-comma invalid pseudos
1639 div.querySelectorAll("*,:x");
1640 rbuggyQSA.push(",.*:");
1641 });
1642 }
1643
1644 if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
1645 docElem.mozMatchesSelector ||
1646 docElem.oMatchesSelector ||
1647 docElem.msMatchesSelector) )) ) {
1648
1649 assert(function( div ) {
1650 // Check to see if it's possible to do matchesSelector
1651 // on a disconnected node (IE 9)
1652 support.disconnectedMatch = matches.call( div, "div" );
1653
1654 // This should fail with an exception
1655 // Gecko does not error, returns false instead
1656 matches.call( div, "[s!='']:x" );
1657 rbuggyMatches.push( "!=", pseudos );
1658 });
1659 }
1660
1661 rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1662 rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1663
1664 /* Contains
1665 ---------------------------------------------------------------------- */
1666
1667 // Element contains another
1668 // Purposefully does not implement inclusive descendent
1669 // As in, an element does not contain itself
1670 contains = rnative.test( docElem.contains ) || docElem.compareDocumentPosition ?
1671 function( a, b ) {
1672 var adown = a.nodeType === 9 ? a.documentElement : a,
1673 bup = b && b.parentNode;
1674 return a === bup || !!( bup && bup.nodeType === 1 && (
1675 adown.contains ?
1676 adown.contains( bup ) :
1677 a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1678 ));
1679 } :
1680 function( a, b ) {
1681 if ( b ) {
1682 while ( (b = b.parentNode) ) {
1683 if ( b === a ) {
1684 return true;
1685 }
1686 }
1687 }
1688 return false;
1689 };
1690
1691 /* Sorting
1692 ---------------------------------------------------------------------- */
1693
1694 // Document order sorting
1695 sortOrder = docElem.compareDocumentPosition ?
1696 function( a, b ) {
1697
1698 // Flag for duplicate removal
1699 if ( a === b ) {
1700 hasDuplicate = true;
1701 return 0;
1702 }
1703
1704 var compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b );
1705
1706 if ( compare ) {
1707 // Disconnected nodes
1708 if ( compare & 1 ||
1709 (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1710
1711 // Choose the first element that is related to our preferred document
1712 if ( a === doc || contains(preferredDoc, a) ) {
1713 return -1;
1714 }
1715 if ( b === doc || contains(preferredDoc, b) ) {
1716 return 1;
1717 }
1718
1719 // Maintain original order
1720 return sortInput ?
1721 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1722 0;
1723 }
1724
1725 return compare & 4 ? -1 : 1;
1726 }
1727
1728 // Not directly comparable, sort on existence of method
1729 return a.compareDocumentPosition ? -1 : 1;
1730 } :
1731 function( a, b ) {
1732 var cur,
1733 i = 0,
1734 aup = a.parentNode,
1735 bup = b.parentNode,
1736 ap = [ a ],
1737 bp = [ b ];
1738
1739 // Exit early if the nodes are identical
1740 if ( a === b ) {
1741 hasDuplicate = true;
1742 return 0;
1743
1744 // Parentless nodes are either documents or disconnected
1745 } else if ( !aup || !bup ) {
1746 return a === doc ? -1 :
1747 b === doc ? 1 :
1748 aup ? -1 :
1749 bup ? 1 :
1750 sortInput ?
1751 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1752 0;
1753
1754 // If the nodes are siblings, we can do a quick check
1755 } else if ( aup === bup ) {
1756 return siblingCheck( a, b );
1757 }
1758
1759 // Otherwise we need full lists of their ancestors for comparison
1760 cur = a;
1761 while ( (cur = cur.parentNode) ) {
1762 ap.unshift( cur );
1763 }
1764 cur = b;
1765 while ( (cur = cur.parentNode) ) {
1766 bp.unshift( cur );
1767 }
1768
1769 // Walk down the tree looking for a discrepancy
1770 while ( ap[i] === bp[i] ) {
1771 i++;
1772 }
1773
1774 return i ?
1775 // Do a sibling check if the nodes have a common ancestor
1776 siblingCheck( ap[i], bp[i] ) :
1777
1778 // Otherwise nodes in our document sort first
1779 ap[i] === preferredDoc ? -1 :
1780 bp[i] === preferredDoc ? 1 :
1781 0;
1782 };
1783
1784 return doc;
1785};
1786
1787Sizzle.matches = function( expr, elements ) {
1788 return Sizzle( expr, null, null, elements );
1789};
1790
1791Sizzle.matchesSelector = function( elem, expr ) {
1792 // Set document vars if needed
1793 if ( ( elem.ownerDocument || elem ) !== document ) {
1794 setDocument( elem );
1795 }
1796
1797 // Make sure that attribute selectors are quoted
1798 expr = expr.replace( rattributeQuotes, "='$1']" );
1799
1800 if ( support.matchesSelector && documentIsHTML &&
1801 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1802 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
1803
1804 try {
1805 var ret = matches.call( elem, expr );
1806
1807 // IE 9's matchesSelector returns false on disconnected nodes
1808 if ( ret || support.disconnectedMatch ||
1809 // As well, disconnected nodes are said to be in a document
1810 // fragment in IE 9
1811 elem.document && elem.document.nodeType !== 11 ) {
1812 return ret;
1813 }
1814 } catch(e) {}
1815 }
1816
1817 return Sizzle( expr, document, null, [elem] ).length > 0;
1818};
1819
1820Sizzle.contains = function( context, elem ) {
1821 // Set document vars if needed
1822 if ( ( context.ownerDocument || context ) !== document ) {
1823 setDocument( context );
1824 }
1825 return contains( context, elem );
1826};
1827
1828Sizzle.attr = function( elem, name ) {
1829 // Set document vars if needed
1830 if ( ( elem.ownerDocument || elem ) !== document ) {
1831 setDocument( elem );
1832 }
1833
1834 var fn = Expr.attrHandle[ name.toLowerCase() ],
1835 // Don't get fooled by Object.prototype properties (jQuery #13807)
1836 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1837 fn( elem, name, !documentIsHTML ) :
1838 undefined;
1839
1840 return val === undefined ?
1841 support.attributes || !documentIsHTML ?
1842 elem.getAttribute( name ) :
1843 (val = elem.getAttributeNode(name)) && val.specified ?
1844 val.value :
1845 null :
1846 val;
1847};
1848
1849Sizzle.error = function( msg ) {
1850 throw new Error( "Syntax error, unrecognized expression: " + msg );
1851};
1852
1853/**
1854 * Document sorting and removing duplicates
1855 * @param {ArrayLike} results
1856 */
1857Sizzle.uniqueSort = function( results ) {
1858 var elem,
1859 duplicates = [],
1860 j = 0,
1861 i = 0;
1862
1863 // Unless we *know* we can detect duplicates, assume their presence
1864 hasDuplicate = !support.detectDuplicates;
1865 sortInput = !support.sortStable && results.slice( 0 );
1866 results.sort( sortOrder );
1867
1868 if ( hasDuplicate ) {
1869 while ( (elem = results[i++]) ) {
1870 if ( elem === results[ i ] ) {
1871 j = duplicates.push( i );
1872 }
1873 }
1874 while ( j-- ) {
1875 results.splice( duplicates[ j ], 1 );
1876 }
1877 }
1878
1879 return results;
1880};
1881
1882/**
1883 * Utility function for retrieving the text value of an array of DOM nodes
1884 * @param {Array|Element} elem
1885 */
1886getText = Sizzle.getText = function( elem ) {
1887 var node,
1888 ret = "",
1889 i = 0,
1890 nodeType = elem.nodeType;
1891
1892 if ( !nodeType ) {
1893 // If no nodeType, this is expected to be an array
1894 for ( ; (node = elem[i]); i++ ) {
1895 // Do not traverse comment nodes
1896 ret += getText( node );
1897 }
1898 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1899 // Use textContent for elements
1900 // innerText usage removed for consistency of new lines (see #11153)
1901 if ( typeof elem.textContent === "string" ) {
1902 return elem.textContent;
1903 } else {
1904 // Traverse its children
1905 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1906 ret += getText( elem );
1907 }
1908 }
1909 } else if ( nodeType === 3 || nodeType === 4 ) {
1910 return elem.nodeValue;
1911 }
1912 // Do not include comment or processing instruction nodes
1913
1914 return ret;
1915};
1916
1917Expr = Sizzle.selectors = {
1918
1919 // Can be adjusted by the user
1920 cacheLength: 50,
1921
1922 createPseudo: markFunction,
1923
1924 match: matchExpr,
1925
1926 attrHandle: {},
1927
1928 find: {},
1929
1930 relative: {
1931 ">": { dir: "parentNode", first: true },
1932 " ": { dir: "parentNode" },
1933 "+": { dir: "previousSibling", first: true },
1934 "~": { dir: "previousSibling" }
1935 },
1936
1937 preFilter: {
1938 "ATTR": function( match ) {
1939 match[1] = match[1].replace( runescape, funescape );
1940
1941 // Move the given value to match[3] whether quoted or unquoted
1942 match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
1943
1944 if ( match[2] === "~=" ) {
1945 match[3] = " " + match[3] + " ";
1946 }
1947
1948 return match.slice( 0, 4 );
1949 },
1950
1951 "CHILD": function( match ) {
1952 /* matches from matchExpr["CHILD"]
1953 1 type (only|nth|...)
1954 2 what (child|of-type)
1955 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1956 4 xn-component of xn+y argument ([+-]?\d*n|)
1957 5 sign of xn-component
1958 6 x of xn-component
1959 7 sign of y-component
1960 8 y of y-component
1961 */
1962 match[1] = match[1].toLowerCase();
1963
1964 if ( match[1].slice( 0, 3 ) === "nth" ) {
1965 // nth-* requires argument
1966 if ( !match[3] ) {
1967 Sizzle.error( match[0] );
1968 }
1969
1970 // numeric x and y parameters for Expr.filter.CHILD
1971 // remember that false/true cast respectively to 0/1
1972 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1973 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1974
1975 // other types prohibit arguments
1976 } else if ( match[3] ) {
1977 Sizzle.error( match[0] );
1978 }
1979
1980 return match;
1981 },
1982
1983 "PSEUDO": function( match ) {
1984 var excess,
1985 unquoted = !match[5] && match[2];
1986
1987 if ( matchExpr["CHILD"].test( match[0] ) ) {
1988 return null;
1989 }
1990
1991 // Accept quoted arguments as-is
1992 if ( match[3] && match[4] !== undefined ) {
1993 match[2] = match[4];
1994
1995 // Strip excess characters from unquoted arguments
1996 } else if ( unquoted && rpseudo.test( unquoted ) &&
1997 // Get excess from tokenize (recursively)
1998 (excess = tokenize( unquoted, true )) &&
1999 // advance to the next closing parenthesis
2000 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
2001
2002 // excess is a negative index
2003 match[0] = match[0].slice( 0, excess );
2004 match[2] = unquoted.slice( 0, excess );
2005 }
2006
2007 // Return only captures needed by the pseudo filter method (type and argument)
2008 return match.slice( 0, 3 );
2009 }
2010 },
2011
2012 filter: {
2013
2014 "TAG": function( nodeNameSelector ) {
2015 var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
2016 return nodeNameSelector === "*" ?
2017 function() { return true; } :
2018 function( elem ) {
2019 return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
2020 };
2021 },
2022
2023 "CLASS": function( className ) {
2024 var pattern = classCache[ className + " " ];
2025
2026 return pattern ||
2027 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
2028 classCache( className, function( elem ) {
2029 return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
2030 });
2031 },
2032
2033 "ATTR": function( name, operator, check ) {
2034 return function( elem ) {
2035 var result = Sizzle.attr( elem, name );
2036
2037 if ( result == null ) {
2038 return operator === "!=";
2039 }
2040 if ( !operator ) {
2041 return true;
2042 }
2043
2044 result += "";
2045
2046 return operator === "=" ? result === check :
2047 operator === "!=" ? result !== check :
2048 operator === "^=" ? check && result.indexOf( check ) === 0 :
2049 operator === "*=" ? check && result.indexOf( check ) > -1 :
2050 operator === "$=" ? check && result.slice( -check.length ) === check :
2051 operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
2052 operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
2053 false;
2054 };
2055 },
2056
2057 "CHILD": function( type, what, argument, first, last ) {
2058 var simple = type.slice( 0, 3 ) !== "nth",
2059 forward = type.slice( -4 ) !== "last",
2060 ofType = what === "of-type";
2061
2062 return first === 1 && last === 0 ?
2063
2064 // Shortcut for :nth-*(n)
2065 function( elem ) {
2066 return !!elem.parentNode;
2067 } :
2068
2069 function( elem, context, xml ) {
2070 var cache, outerCache, node, diff, nodeIndex, start,
2071 dir = simple !== forward ? "nextSibling" : "previousSibling",
2072 parent = elem.parentNode,
2073 name = ofType && elem.nodeName.toLowerCase(),
2074 useCache = !xml && !ofType;
2075
2076 if ( parent ) {
2077
2078 // :(first|last|only)-(child|of-type)
2079 if ( simple ) {
2080 while ( dir ) {
2081 node = elem;
2082 while ( (node = node[ dir ]) ) {
2083 if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
2084 return false;
2085 }
2086 }
2087 // Reverse direction for :only-* (if we haven't yet done so)
2088 start = dir = type === "only" && !start && "nextSibling";
2089 }
2090 return true;
2091 }
2092
2093 start = [ forward ? parent.firstChild : parent.lastChild ];
2094
2095 // non-xml :nth-child(...) stores cache data on `parent`
2096 if ( forward && useCache ) {
2097 // Seek `elem` from a previously-cached index
2098 outerCache = parent[ expando ] || (parent[ expando ] = {});
2099 cache = outerCache[ type ] || [];
2100 nodeIndex = cache[0] === dirruns && cache[1];
2101 diff = cache[0] === dirruns && cache[2];
2102 node = nodeIndex && parent.childNodes[ nodeIndex ];
2103
2104 while ( (node = ++nodeIndex && node && node[ dir ] ||
2105
2106 // Fallback to seeking `elem` from the start
2107 (diff = nodeIndex = 0) || start.pop()) ) {
2108
2109 // When found, cache indexes on `parent` and break
2110 if ( node.nodeType === 1 && ++diff && node === elem ) {
2111 outerCache[ type ] = [ dirruns, nodeIndex, diff ];
2112 break;
2113 }
2114 }
2115
2116 // Use previously-cached element index if available
2117 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
2118 diff = cache[1];
2119
2120 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
2121 } else {
2122 // Use the same loop as above to seek `elem` from the start
2123 while ( (node = ++nodeIndex && node && node[ dir ] ||
2124 (diff = nodeIndex = 0) || start.pop()) ) {
2125
2126 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
2127 // Cache the index of each encountered element
2128 if ( useCache ) {
2129 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
2130 }
2131
2132 if ( node === elem ) {
2133 break;
2134 }
2135 }
2136 }
2137 }
2138
2139 // Incorporate the offset, then check against cycle size
2140 diff -= last;
2141 return diff === first || ( diff % first === 0 && diff / first >= 0 );
2142 }
2143 };
2144 },
2145
2146 "PSEUDO": function( pseudo, argument ) {
2147 // pseudo-class names are case-insensitive
2148 // http://www.w3.org/TR/selectors/#pseudo-classes
2149 // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
2150 // Remember that setFilters inherits from pseudos
2151 var args,
2152 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
2153 Sizzle.error( "unsupported pseudo: " + pseudo );
2154
2155 // The user may use createPseudo to indicate that
2156 // arguments are needed to create the filter function
2157 // just as Sizzle does
2158 if ( fn[ expando ] ) {
2159 return fn( argument );
2160 }
2161
2162 // But maintain support for old signatures
2163 if ( fn.length > 1 ) {
2164 args = [ pseudo, pseudo, "", argument ];
2165 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
2166 markFunction(function( seed, matches ) {
2167 var idx,
2168 matched = fn( seed, argument ),
2169 i = matched.length;
2170 while ( i-- ) {
2171 idx = indexOf.call( seed, matched[i] );
2172 seed[ idx ] = !( matches[ idx ] = matched[i] );
2173 }
2174 }) :
2175 function( elem ) {
2176 return fn( elem, 0, args );
2177 };
2178 }
2179
2180 return fn;
2181 }
2182 },
2183
2184 pseudos: {
2185 // Potentially complex pseudos
2186 "not": markFunction(function( selector ) {
2187 // Trim the selector passed to compile
2188 // to avoid treating leading and trailing
2189 // spaces as combinators
2190 var input = [],
2191 results = [],
2192 matcher = compile( selector.replace( rtrim, "$1" ) );
2193
2194 return matcher[ expando ] ?
2195 markFunction(function( seed, matches, context, xml ) {
2196 var elem,
2197 unmatched = matcher( seed, null, xml, [] ),
2198 i = seed.length;
2199
2200 // Match elements unmatched by `matcher`
2201 while ( i-- ) {
2202 if ( (elem = unmatched[i]) ) {
2203 seed[i] = !(matches[i] = elem);
2204 }
2205 }
2206 }) :
2207 function( elem, context, xml ) {
2208 input[0] = elem;
2209 matcher( input, null, xml, results );
2210 return !results.pop();
2211 };
2212 }),
2213
2214 "has": markFunction(function( selector ) {
2215 return function( elem ) {
2216 return Sizzle( selector, elem ).length > 0;
2217 };
2218 }),
2219
2220 "contains": markFunction(function( text ) {
2221 return function( elem ) {
2222 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2223 };
2224 }),
2225
2226 // "Whether an element is represented by a :lang() selector
2227 // is based solely on the element's language value
2228 // being equal to the identifier C,
2229 // or beginning with the identifier C immediately followed by "-".
2230 // The matching of C against the element's language value is performed case-insensitively.
2231 // The identifier C does not have to be a valid language name."
2232 // http://www.w3.org/TR/selectors/#lang-pseudo
2233 "lang": markFunction( function( lang ) {
2234 // lang value must be a valid identifier
2235 if ( !ridentifier.test(lang || "") ) {
2236 Sizzle.error( "unsupported lang: " + lang );
2237 }
2238 lang = lang.replace( runescape, funescape ).toLowerCase();
2239 return function( elem ) {
2240 var elemLang;
2241 do {
2242 if ( (elemLang = documentIsHTML ?
2243 elem.lang :
2244 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2245
2246 elemLang = elemLang.toLowerCase();
2247 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2248 }
2249 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2250 return false;
2251 };
2252 }),
2253
2254 // Miscellaneous
2255 "target": function( elem ) {
2256 var hash = window.location && window.location.hash;
2257 return hash && hash.slice( 1 ) === elem.id;
2258 },
2259
2260 "root": function( elem ) {
2261 return elem === docElem;
2262 },
2263
2264 "focus": function( elem ) {
2265 return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2266 },
2267
2268 // Boolean properties
2269 "enabled": function( elem ) {
2270 return elem.disabled === false;
2271 },
2272
2273 "disabled": function( elem ) {
2274 return elem.disabled === true;
2275 },
2276
2277 "checked": function( elem ) {
2278 // In CSS3, :checked should return both checked and selected elements
2279 // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2280 var nodeName = elem.nodeName.toLowerCase();
2281 return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2282 },
2283
2284 "selected": function( elem ) {
2285 // Accessing this property makes selected-by-default
2286 // options in Safari work properly
2287 if ( elem.parentNode ) {
2288 elem.parentNode.selectedIndex;
2289 }
2290
2291 return elem.selected === true;
2292 },
2293
2294 // Contents
2295 "empty": function( elem ) {
2296 // http://www.w3.org/TR/selectors/#empty-pseudo
2297 // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
2298 // not comment, processing instructions, or others
2299 // Thanks to Diego Perini for the nodeName shortcut
2300 // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
2301 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2302 if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
2303 return false;
2304 }
2305 }
2306 return true;
2307 },
2308
2309 "parent": function( elem ) {
2310 return !Expr.pseudos["empty"]( elem );
2311 },
2312
2313 // Element/input types
2314 "header": function( elem ) {
2315 return rheader.test( elem.nodeName );
2316 },
2317
2318 "input": function( elem ) {
2319 return rinputs.test( elem.nodeName );
2320 },
2321
2322 "button": function( elem ) {
2323 var name = elem.nodeName.toLowerCase();
2324 return name === "input" && elem.type === "button" || name === "button";
2325 },
2326
2327 "text": function( elem ) {
2328 var attr;
2329 // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
2330 // use getAttribute instead to test this case
2331 return elem.nodeName.toLowerCase() === "input" &&
2332 elem.type === "text" &&
2333 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
2334 },
2335
2336 // Position-in-collection
2337 "first": createPositionalPseudo(function() {
2338 return [ 0 ];
2339 }),
2340
2341 "last": createPositionalPseudo(function( matchIndexes, length ) {
2342 return [ length - 1 ];
2343 }),
2344
2345 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2346 return [ argument < 0 ? argument + length : argument ];
2347 }),
2348
2349 "even": createPositionalPseudo(function( matchIndexes, length ) {
2350 var i = 0;
2351 for ( ; i < length; i += 2 ) {
2352 matchIndexes.push( i );
2353 }
2354 return matchIndexes;
2355 }),
2356
2357 "odd": createPositionalPseudo(function( matchIndexes, length ) {
2358 var i = 1;
2359 for ( ; i < length; i += 2 ) {
2360 matchIndexes.push( i );
2361 }
2362 return matchIndexes;
2363 }),
2364
2365 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2366 var i = argument < 0 ? argument + length : argument;
2367 for ( ; --i >= 0; ) {
2368 matchIndexes.push( i );
2369 }
2370 return matchIndexes;
2371 }),
2372
2373 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2374 var i = argument < 0 ? argument + length : argument;
2375 for ( ; ++i < length; ) {
2376 matchIndexes.push( i );
2377 }
2378 return matchIndexes;
2379 })
2380 }
2381};
2382
2383Expr.pseudos["nth"] = Expr.pseudos["eq"];
2384
2385// Add button/input type pseudos
2386for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2387 Expr.pseudos[ i ] = createInputPseudo( i );
2388}
2389for ( i in { submit: true, reset: true } ) {
2390 Expr.pseudos[ i ] = createButtonPseudo( i );
2391}
2392
2393// Easy API for creating new setFilters
2394function setFilters() {}
2395setFilters.prototype = Expr.filters = Expr.pseudos;
2396Expr.setFilters = new setFilters();
2397
2398function tokenize( selector, parseOnly ) {
2399 var matched, match, tokens, type,
2400 soFar, groups, preFilters,
2401 cached = tokenCache[ selector + " " ];
2402
2403 if ( cached ) {
2404 return parseOnly ? 0 : cached.slice( 0 );
2405 }
2406
2407 soFar = selector;
2408 groups = [];
2409 preFilters = Expr.preFilter;
2410
2411 while ( soFar ) {
2412
2413 // Comma and first run
2414 if ( !matched || (match = rcomma.exec( soFar )) ) {
2415 if ( match ) {
2416 // Don't consume trailing commas as valid
2417 soFar = soFar.slice( match[0].length ) || soFar;
2418 }
2419 groups.push( tokens = [] );
2420 }
2421
2422 matched = false;
2423
2424 // Combinators
2425 if ( (match = rcombinators.exec( soFar )) ) {
2426 matched = match.shift();
2427 tokens.push({
2428 value: matched,
2429 // Cast descendant combinators to space
2430 type: match[0].replace( rtrim, " " )
2431 });
2432 soFar = soFar.slice( matched.length );
2433 }
2434
2435 // Filters
2436 for ( type in Expr.filter ) {
2437 if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2438 (match = preFilters[ type ]( match ))) ) {
2439 matched = match.shift();
2440 tokens.push({
2441 value: matched,
2442 type: type,
2443 matches: match
2444 });
2445 soFar = soFar.slice( matched.length );
2446 }
2447 }
2448
2449 if ( !matched ) {
2450 break;
2451 }
2452 }
2453
2454 // Return the length of the invalid excess
2455 // if we're just parsing
2456 // Otherwise, throw an error or return tokens
2457 return parseOnly ?
2458 soFar.length :
2459 soFar ?
2460 Sizzle.error( selector ) :
2461 // Cache the tokens
2462 tokenCache( selector, groups ).slice( 0 );
2463}
2464
2465function toSelector( tokens ) {
2466 var i = 0,
2467 len = tokens.length,
2468 selector = "";
2469 for ( ; i < len; i++ ) {
2470 selector += tokens[i].value;
2471 }
2472 return selector;
2473}
2474
2475function addCombinator( matcher, combinator, base ) {
2476 var dir = combinator.dir,
2477 checkNonElements = base && dir === "parentNode",
2478 doneName = done++;
2479
2480 return combinator.first ?
2481 // Check against closest ancestor/preceding element
2482 function( elem, context, xml ) {
2483 while ( (elem = elem[ dir ]) ) {
2484 if ( elem.nodeType === 1 || checkNonElements ) {
2485 return matcher( elem, context, xml );
2486 }
2487 }
2488 } :
2489
2490 // Check against all ancestor/preceding elements
2491 function( elem, context, xml ) {
2492 var data, cache, outerCache,
2493 dirkey = dirruns + " " + doneName;
2494
2495 // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2496 if ( xml ) {
2497 while ( (elem = elem[ dir ]) ) {
2498 if ( elem.nodeType === 1 || checkNonElements ) {
2499 if ( matcher( elem, context, xml ) ) {
2500 return true;
2501 }
2502 }
2503 }
2504 } else {
2505 while ( (elem = elem[ dir ]) ) {
2506 if ( elem.nodeType === 1 || checkNonElements ) {
2507 outerCache = elem[ expando ] || (elem[ expando ] = {});
2508 if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
2509 if ( (data = cache[1]) === true || data === cachedruns ) {
2510 return data === true;
2511 }
2512 } else {
2513 cache = outerCache[ dir ] = [ dirkey ];
2514 cache[1] = matcher( elem, context, xml ) || cachedruns;
2515 if ( cache[1] === true ) {
2516 return true;
2517 }
2518 }
2519 }
2520 }
2521 }
2522 };
2523}
2524
2525function elementMatcher( matchers ) {
2526 return matchers.length > 1 ?
2527 function( elem, context, xml ) {
2528 var i = matchers.length;
2529 while ( i-- ) {
2530 if ( !matchers[i]( elem, context, xml ) ) {
2531 return false;
2532 }
2533 }
2534 return true;
2535 } :
2536 matchers[0];
2537}
2538
2539function condense( unmatched, map, filter, context, xml ) {
2540 var elem,
2541 newUnmatched = [],
2542 i = 0,
2543 len = unmatched.length,
2544 mapped = map != null;
2545
2546 for ( ; i < len; i++ ) {
2547 if ( (elem = unmatched[i]) ) {
2548 if ( !filter || filter( elem, context, xml ) ) {
2549 newUnmatched.push( elem );
2550 if ( mapped ) {
2551 map.push( i );
2552 }
2553 }
2554 }
2555 }
2556
2557 return newUnmatched;
2558}
2559
2560function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2561 if ( postFilter && !postFilter[ expando ] ) {
2562 postFilter = setMatcher( postFilter );
2563 }
2564 if ( postFinder && !postFinder[ expando ] ) {
2565 postFinder = setMatcher( postFinder, postSelector );
2566 }
2567 return markFunction(function( seed, results, context, xml ) {
2568 var temp, i, elem,
2569 preMap = [],
2570 postMap = [],
2571 preexisting = results.length,
2572
2573 // Get initial elements from seed or context
2574 elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2575
2576 // Prefilter to get matcher input, preserving a map for seed-results synchronization
2577 matcherIn = preFilter && ( seed || !selector ) ?
2578 condense( elems, preMap, preFilter, context, xml ) :
2579 elems,
2580
2581 matcherOut = matcher ?
2582 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2583 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2584
2585 // ...intermediate processing is necessary
2586 [] :
2587
2588 // ...otherwise use results directly
2589 results :
2590 matcherIn;
2591
2592 // Find primary matches
2593 if ( matcher ) {
2594 matcher( matcherIn, matcherOut, context, xml );
2595 }
2596
2597 // Apply postFilter
2598 if ( postFilter ) {
2599 temp = condense( matcherOut, postMap );
2600 postFilter( temp, [], context, xml );
2601
2602 // Un-match failing elements by moving them back to matcherIn
2603 i = temp.length;
2604 while ( i-- ) {
2605 if ( (elem = temp[i]) ) {
2606 matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2607 }
2608 }
2609 }
2610
2611 if ( seed ) {
2612 if ( postFinder || preFilter ) {
2613 if ( postFinder ) {
2614 // Get the final matcherOut by condensing this intermediate into postFinder contexts
2615 temp = [];
2616 i = matcherOut.length;
2617 while ( i-- ) {
2618 if ( (elem = matcherOut[i]) ) {
2619 // Restore matcherIn since elem is not yet a final match
2620 temp.push( (matcherIn[i] = elem) );
2621 }
2622 }
2623 postFinder( null, (matcherOut = []), temp, xml );
2624 }
2625
2626 // Move matched elements from seed to results to keep them synchronized
2627 i = matcherOut.length;
2628 while ( i-- ) {
2629 if ( (elem = matcherOut[i]) &&
2630 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2631
2632 seed[temp] = !(results[temp] = elem);
2633 }
2634 }
2635 }
2636
2637 // Add elements to results, through postFinder if defined
2638 } else {
2639 matcherOut = condense(
2640 matcherOut === results ?
2641 matcherOut.splice( preexisting, matcherOut.length ) :
2642 matcherOut
2643 );
2644 if ( postFinder ) {
2645 postFinder( null, results, matcherOut, xml );
2646 } else {
2647 push.apply( results, matcherOut );
2648 }
2649 }
2650 });
2651}
2652
2653function matcherFromTokens( tokens ) {
2654 var checkContext, matcher, j,
2655 len = tokens.length,
2656 leadingRelative = Expr.relative[ tokens[0].type ],
2657 implicitRelative = leadingRelative || Expr.relative[" "],
2658 i = leadingRelative ? 1 : 0,
2659
2660 // The foundational matcher ensures that elements are reachable from top-level context(s)
2661 matchContext = addCombinator( function( elem ) {
2662 return elem === checkContext;
2663 }, implicitRelative, true ),
2664 matchAnyContext = addCombinator( function( elem ) {
2665 return indexOf.call( checkContext, elem ) > -1;
2666 }, implicitRelative, true ),
2667 matchers = [ function( elem, context, xml ) {
2668 return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2669 (checkContext = context).nodeType ?
2670 matchContext( elem, context, xml ) :
2671 matchAnyContext( elem, context, xml ) );
2672 } ];
2673
2674 for ( ; i < len; i++ ) {
2675 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2676 matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2677 } else {
2678 matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2679
2680 // Return special upon seeing a positional matcher
2681 if ( matcher[ expando ] ) {
2682 // Find the next relative operator (if any) for proper handling
2683 j = ++i;
2684 for ( ; j < len; j++ ) {
2685 if ( Expr.relative[ tokens[j].type ] ) {
2686 break;
2687 }
2688 }
2689 return setMatcher(
2690 i > 1 && elementMatcher( matchers ),
2691 i > 1 && toSelector(
2692 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2693 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2694 ).replace( rtrim, "$1" ),
2695 matcher,
2696 i < j && matcherFromTokens( tokens.slice( i, j ) ),
2697 j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2698 j < len && toSelector( tokens )
2699 );
2700 }
2701 matchers.push( matcher );
2702 }
2703 }
2704
2705 return elementMatcher( matchers );
2706}
2707
2708function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2709 // A counter to specify which element is currently being matched
2710 var matcherCachedRuns = 0,
2711 bySet = setMatchers.length > 0,
2712 byElement = elementMatchers.length > 0,
2713 superMatcher = function( seed, context, xml, results, expandContext ) {
2714 var elem, j, matcher,
2715 setMatched = [],
2716 matchedCount = 0,
2717 i = "0",
2718 unmatched = seed && [],
2719 outermost = expandContext != null,
2720 contextBackup = outermostContext,
2721 // We must always have either seed elements or context
2722 elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
2723 // Use integer dirruns iff this is the outermost matcher
2724 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
2725
2726 if ( outermost ) {
2727 outermostContext = context !== document && context;
2728 cachedruns = matcherCachedRuns;
2729 }
2730
2731 // Add elements passing elementMatchers directly to results
2732 // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2733 for ( ; (elem = elems[i]) != null; i++ ) {
2734 if ( byElement && elem ) {
2735 j = 0;
2736 while ( (matcher = elementMatchers[j++]) ) {
2737 if ( matcher( elem, context, xml ) ) {
2738 results.push( elem );
2739 break;
2740 }
2741 }
2742 if ( outermost ) {
2743 dirruns = dirrunsUnique;
2744 cachedruns = ++matcherCachedRuns;
2745 }
2746 }
2747
2748 // Track unmatched elements for set filters
2749 if ( bySet ) {
2750 // They will have gone through all possible matchers
2751 if ( (elem = !matcher && elem) ) {
2752 matchedCount--;
2753 }
2754
2755 // Lengthen the array for every element, matched or not
2756 if ( seed ) {
2757 unmatched.push( elem );
2758 }
2759 }
2760 }
2761
2762 // Apply set filters to unmatched elements
2763 matchedCount += i;
2764 if ( bySet && i !== matchedCount ) {
2765 j = 0;
2766 while ( (matcher = setMatchers[j++]) ) {
2767 matcher( unmatched, setMatched, context, xml );
2768 }
2769
2770 if ( seed ) {
2771 // Reintegrate element matches to eliminate the need for sorting
2772 if ( matchedCount > 0 ) {
2773 while ( i-- ) {
2774 if ( !(unmatched[i] || setMatched[i]) ) {
2775 setMatched[i] = pop.call( results );
2776 }
2777 }
2778 }
2779
2780 // Discard index placeholder values to get only actual matches
2781 setMatched = condense( setMatched );
2782 }
2783
2784 // Add matches to results
2785 push.apply( results, setMatched );
2786
2787 // Seedless set matches succeeding multiple successful matchers stipulate sorting
2788 if ( outermost && !seed && setMatched.length > 0 &&
2789 ( matchedCount + setMatchers.length ) > 1 ) {
2790
2791 Sizzle.uniqueSort( results );
2792 }
2793 }
2794
2795 // Override manipulation of globals by nested matchers
2796 if ( outermost ) {
2797 dirruns = dirrunsUnique;
2798 outermostContext = contextBackup;
2799 }
2800
2801 return unmatched;
2802 };
2803
2804 return bySet ?
2805 markFunction( superMatcher ) :
2806 superMatcher;
2807}
2808
2809compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
2810 var i,
2811 setMatchers = [],
2812 elementMatchers = [],
2813 cached = compilerCache[ selector + " " ];
2814
2815 if ( !cached ) {
2816 // Generate a function of recursive functions that can be used to check each element
2817 if ( !group ) {
2818 group = tokenize( selector );
2819 }
2820 i = group.length;
2821 while ( i-- ) {
2822 cached = matcherFromTokens( group[i] );
2823 if ( cached[ expando ] ) {
2824 setMatchers.push( cached );
2825 } else {
2826 elementMatchers.push( cached );
2827 }
2828 }
2829
2830 // Cache the compiled function
2831 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2832 }
2833 return cached;
2834};
2835
2836function multipleContexts( selector, contexts, results ) {
2837 var i = 0,
2838 len = contexts.length;
2839 for ( ; i < len; i++ ) {
2840 Sizzle( selector, contexts[i], results );
2841 }
2842 return results;
2843}
2844
2845function select( selector, context, results, seed ) {
2846 var i, tokens, token, type, find,
2847 match = tokenize( selector );
2848
2849 if ( !seed ) {
2850 // Try to minimize operations if there is only one group
2851 if ( match.length === 1 ) {
2852
2853 // Take a shortcut and set the context if the root selector is an ID
2854 tokens = match[0] = match[0].slice( 0 );
2855 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2856 support.getById && context.nodeType === 9 && documentIsHTML &&
2857 Expr.relative[ tokens[1].type ] ) {
2858
2859 context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2860 if ( !context ) {
2861 return results;
2862 }
2863 selector = selector.slice( tokens.shift().value.length );
2864 }
2865
2866 // Fetch a seed set for right-to-left matching
2867 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2868 while ( i-- ) {
2869 token = tokens[i];
2870
2871 // Abort if we hit a combinator
2872 if ( Expr.relative[ (type = token.type) ] ) {
2873 break;
2874 }
2875 if ( (find = Expr.find[ type ]) ) {
2876 // Search, expanding context for leading sibling combinators
2877 if ( (seed = find(
2878 token.matches[0].replace( runescape, funescape ),
2879 rsibling.test( tokens[0].type ) && context.parentNode || context
2880 )) ) {
2881
2882 // If seed is empty or no tokens remain, we can return early
2883 tokens.splice( i, 1 );
2884 selector = seed.length && toSelector( tokens );
2885 if ( !selector ) {
2886 push.apply( results, seed );
2887 return results;
2888 }
2889
2890 break;
2891 }
2892 }
2893 }
2894 }
2895 }
2896
2897 // Compile and execute a filtering function
2898 // Provide `match` to avoid retokenization if we modified the selector above
2899 compile( selector, match )(
2900 seed,
2901 context,
2902 !documentIsHTML,
2903 results,
2904 rsibling.test( selector )
2905 );
2906 return results;
2907}
2908
2909// One-time assignments
2910
2911// Sort stability
2912support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2913
2914// Support: Chrome<14
2915// Always assume duplicates if they aren't passed to the comparison function
2916support.detectDuplicates = hasDuplicate;
2917
2918// Initialize against the default document
2919setDocument();
2920
2921// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2922// Detached nodes confoundingly follow *each other*
2923support.sortDetached = assert(function( div1 ) {
2924 // Should return 1, but returns 4 (following)
2925 return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2926});
2927
2928// Support: IE<8
2929// Prevent attribute/property "interpolation"
2930// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2931if ( !assert(function( div ) {
2932 div.innerHTML = "<a href='#'></a>";
2933 return div.firstChild.getAttribute("href") === "#" ;
2934}) ) {
2935 addHandle( "type|href|height|width", function( elem, name, isXML ) {
2936 if ( !isXML ) {
2937 return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2938 }
2939 });
2940}
2941
2942// Support: IE<9
2943// Use defaultValue in place of getAttribute("value")
2944if ( !support.attributes || !assert(function( div ) {
2945 div.innerHTML = "<input/>";
2946 div.firstChild.setAttribute( "value", "" );
2947 return div.firstChild.getAttribute( "value" ) === "";
2948}) ) {
2949 addHandle( "value", function( elem, name, isXML ) {
2950 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2951 return elem.defaultValue;
2952 }
2953 });
2954}
2955
2956// Support: IE<9
2957// Use getAttributeNode to fetch booleans when getAttribute lies
2958if ( !assert(function( div ) {
2959 return div.getAttribute("disabled") == null;
2960}) ) {
2961 addHandle( booleans, function( elem, name, isXML ) {
2962 var val;
2963 if ( !isXML ) {
2964 return (val = elem.getAttributeNode( name )) && val.specified ?
2965 val.value :
2966 elem[ name ] === true ? name.toLowerCase() : null;
2967 }
2968 });
2969}
2970
2971jQuery.find = Sizzle;
2972jQuery.expr = Sizzle.selectors;
2973jQuery.expr[":"] = jQuery.expr.pseudos;
2974jQuery.unique = Sizzle.uniqueSort;
2975jQuery.text = Sizzle.getText;
2976jQuery.isXMLDoc = Sizzle.isXML;
2977jQuery.contains = Sizzle.contains;
2978
2979
2980})( window );
2981// String to Object options format cache
2982var optionsCache = {};
2983
2984// Convert String-formatted options into Object-formatted ones and store in cache
2985function createOptions( options ) {
2986 var object = optionsCache[ options ] = {};
2987 jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
2988 object[ flag ] = true;
2989 });
2990 return object;
2991}
2992
2993/*
2994 * Create a callback list using the following parameters:
2995 *
2996 * options: an optional list of space-separated options that will change how
2997 * the callback list behaves or a more traditional option object
2998 *
2999 * By default a callback list will act like an event callback list and can be
3000 * "fired" multiple times.
3001 *
3002 * Possible options:
3003 *
3004 * once: will ensure the callback list can only be fired once (like a Deferred)
3005 *
3006 * memory: will keep track of previous values and will call any callback added
3007 * after the list has been fired right away with the latest "memorized"
3008 * values (like a Deferred)
3009 *
3010 * unique: will ensure a callback can only be added once (no duplicate in the list)
3011 *
3012 * stopOnFalse: interrupt callings when a callback returns false
3013 *
3014 */
3015jQuery.Callbacks = function( options ) {
3016
3017 // Convert options from String-formatted to Object-formatted if needed
3018 // (we check in cache first)
3019 options = typeof options === "string" ?
3020 ( optionsCache[ options ] || createOptions( options ) ) :
3021 jQuery.extend( {}, options );
3022
3023 var // Flag to know if list is currently firing
3024 firing,
3025 // Last fire value (for non-forgettable lists)
3026 memory,
3027 // Flag to know if list was already fired
3028 fired,
3029 // End of the loop when firing
3030 firingLength,
3031 // Index of currently firing callback (modified by remove if needed)
3032 firingIndex,
3033 // First callback to fire (used internally by add and fireWith)
3034 firingStart,
3035 // Actual callback list
3036 list = [],
3037 // Stack of fire calls for repeatable lists
3038 stack = !options.once && [],
3039 // Fire callbacks
3040 fire = function( data ) {
3041 memory = options.memory && data;
3042 fired = true;
3043 firingIndex = firingStart || 0;
3044 firingStart = 0;
3045 firingLength = list.length;
3046 firing = true;
3047 for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3048 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3049 memory = false; // To prevent further calls using add
3050 break;
3051 }
3052 }
3053 firing = false;
3054 if ( list ) {
3055 if ( stack ) {
3056 if ( stack.length ) {
3057 fire( stack.shift() );
3058 }
3059 } else if ( memory ) {
3060 list = [];
3061 } else {
3062 self.disable();
3063 }
3064 }
3065 },
3066 // Actual Callbacks object
3067 self = {
3068 // Add a callback or a collection of callbacks to the list
3069 add: function() {
3070 if ( list ) {
3071 // First, we save the current length
3072 var start = list.length;
3073 (function add( args ) {
3074 jQuery.each( args, function( _, arg ) {
3075 var type = jQuery.type( arg );
3076 if ( type === "function" ) {
3077 if ( !options.unique || !self.has( arg ) ) {
3078 list.push( arg );
3079 }
3080 } else if ( arg && arg.length && type !== "string" ) {
3081 // Inspect recursively
3082 add( arg );
3083 }
3084 });
3085 })( arguments );
3086 // Do we need to add the callbacks to the
3087 // current firing batch?
3088 if ( firing ) {
3089 firingLength = list.length;
3090 // With memory, if we're not firing then
3091 // we should call right away
3092 } else if ( memory ) {
3093 firingStart = start;
3094 fire( memory );
3095 }
3096 }
3097 return this;
3098 },
3099 // Remove a callback from the list
3100 remove: function() {
3101 if ( list ) {
3102 jQuery.each( arguments, function( _, arg ) {
3103 var index;
3104 while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3105 list.splice( index, 1 );
3106 // Handle firing indexes
3107 if ( firing ) {
3108 if ( index <= firingLength ) {
3109 firingLength--;
3110 }
3111 if ( index <= firingIndex ) {
3112 firingIndex--;
3113 }
3114 }
3115 }
3116 });
3117 }
3118 return this;
3119 },
3120 // Check if a given callback is in the list.
3121 // If no argument is given, return whether or not list has callbacks attached.
3122 has: function( fn ) {
3123 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3124 },
3125 // Remove all callbacks from the list
3126 empty: function() {
3127 list = [];
3128 firingLength = 0;
3129 return this;
3130 },
3131 // Have the list do nothing anymore
3132 disable: function() {
3133 list = stack = memory = undefined;
3134 return this;
3135 },
3136 // Is it disabled?
3137 disabled: function() {
3138 return !list;
3139 },
3140 // Lock the list in its current state
3141 lock: function() {
3142 stack = undefined;
3143 if ( !memory ) {
3144 self.disable();
3145 }
3146 return this;
3147 },
3148 // Is it locked?
3149 locked: function() {
3150 return !stack;
3151 },
3152 // Call all callbacks with the given context and arguments
3153 fireWith: function( context, args ) {
3154 if ( list && ( !fired || stack ) ) {
3155 args = args || [];
3156 args = [ context, args.slice ? args.slice() : args ];
3157 if ( firing ) {
3158 stack.push( args );
3159 } else {
3160 fire( args );
3161 }
3162 }
3163 return this;
3164 },
3165 // Call all the callbacks with the given arguments
3166 fire: function() {
3167 self.fireWith( this, arguments );
3168 return this;
3169 },
3170 // To know if the callbacks have already been called at least once
3171 fired: function() {
3172 return !!fired;
3173 }
3174 };
3175
3176 return self;
3177};
3178jQuery.extend({
3179
3180 Deferred: function( func ) {
3181 var tuples = [
3182 // action, add listener, listener list, final state
3183 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3184 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3185 [ "notify", "progress", jQuery.Callbacks("memory") ]
3186 ],
3187 state = "pending",
3188 promise = {
3189 state: function() {
3190 return state;
3191 },
3192 always: function() {
3193 deferred.done( arguments ).fail( arguments );
3194 return this;
3195 },
3196 then: function( /* fnDone, fnFail, fnProgress */ ) {
3197 var fns = arguments;
3198 return jQuery.Deferred(function( newDefer ) {
3199 jQuery.each( tuples, function( i, tuple ) {
3200 var action = tuple[ 0 ],
3201 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3202 // deferred[ done | fail | progress ] for forwarding actions to newDefer
3203 deferred[ tuple[1] ](function() {
3204 var returned = fn && fn.apply( this, arguments );
3205 if ( returned && jQuery.isFunction( returned.promise ) ) {
3206 returned.promise()
3207 .done( newDefer.resolve )
3208 .fail( newDefer.reject )
3209 .progress( newDefer.notify );
3210 } else {
3211 newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3212 }
3213 });
3214 });
3215 fns = null;
3216 }).promise();
3217 },
3218 // Get a promise for this deferred
3219 // If obj is provided, the promise aspect is added to the object
3220 promise: function( obj ) {
3221 return obj != null ? jQuery.extend( obj, promise ) : promise;
3222 }
3223 },
3224 deferred = {};
3225
3226 // Keep pipe for back-compat
3227 promise.pipe = promise.then;
3228
3229 // Add list-specific methods
3230 jQuery.each( tuples, function( i, tuple ) {
3231 var list = tuple[ 2 ],
3232 stateString = tuple[ 3 ];
3233
3234 // promise[ done | fail | progress ] = list.add
3235 promise[ tuple[1] ] = list.add;
3236
3237 // Handle state
3238 if ( stateString ) {
3239 list.add(function() {
3240 // state = [ resolved | rejected ]
3241 state = stateString;
3242
3243 // [ reject_list | resolve_list ].disable; progress_list.lock
3244 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3245 }
3246
3247 // deferred[ resolve | reject | notify ]
3248 deferred[ tuple[0] ] = function() {
3249 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3250 return this;
3251 };
3252 deferred[ tuple[0] + "With" ] = list.fireWith;
3253 });
3254
3255 // Make the deferred a promise
3256 promise.promise( deferred );
3257
3258 // Call given func if any
3259 if ( func ) {
3260 func.call( deferred, deferred );
3261 }
3262
3263 // All done!
3264 return deferred;
3265 },
3266
3267 // Deferred helper
3268 when: function( subordinate /* , ..., subordinateN */ ) {
3269 var i = 0,
3270 resolveValues = core_slice.call( arguments ),
3271 length = resolveValues.length,
3272
3273 // the count of uncompleted subordinates
3274 remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3275
3276 // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3277 deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3278
3279 // Update function for both resolve and progress values
3280 updateFunc = function( i, contexts, values ) {
3281 return function( value ) {
3282 contexts[ i ] = this;
3283 values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
3284 if( values === progressValues ) {
3285 deferred.notifyWith( contexts, values );
3286 } else if ( !( --remaining ) ) {
3287 deferred.resolveWith( contexts, values );
3288 }
3289 };
3290 },
3291
3292 progressValues, progressContexts, resolveContexts;
3293
3294 // add listeners to Deferred subordinates; treat others as resolved
3295 if ( length > 1 ) {
3296 progressValues = new Array( length );
3297 progressContexts = new Array( length );
3298 resolveContexts = new Array( length );
3299 for ( ; i < length; i++ ) {
3300 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3301 resolveValues[ i ].promise()
3302 .done( updateFunc( i, resolveContexts, resolveValues ) )
3303 .fail( deferred.reject )
3304 .progress( updateFunc( i, progressContexts, progressValues ) );
3305 } else {
3306 --remaining;
3307 }
3308 }
3309 }
3310
3311 // if we're not waiting on anything, resolve the master
3312 if ( !remaining ) {
3313 deferred.resolveWith( resolveContexts, resolveValues );
3314 }
3315
3316 return deferred.promise();
3317 }
3318});
3319jQuery.support = (function( support ) {
3320
3321 var all, a, input, select, fragment, opt, eventName, isSupported, i,
3322 div = document.createElement("div");
3323
3324 // Setup
3325 div.setAttribute( "className", "t" );
3326 div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
3327
3328 // Finish early in limited (non-browser) environments
3329 all = div.getElementsByTagName("*") || [];
3330 a = div.getElementsByTagName("a")[ 0 ];
3331 if ( !a || !a.style || !all.length ) {
3332 return support;
3333 }
3334
3335 // First batch of tests
3336 select = document.createElement("select");
3337 opt = select.appendChild( document.createElement("option") );
3338 input = div.getElementsByTagName("input")[ 0 ];
3339
3340 a.style.cssText = "top:1px;float:left;opacity:.5";
3341
3342 // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
3343 support.getSetAttribute = div.className !== "t";
3344
3345 // IE strips leading whitespace when .innerHTML is used
3346 support.leadingWhitespace = div.firstChild.nodeType === 3;
3347
3348 // Make sure that tbody elements aren't automatically inserted
3349 // IE will insert them into empty tables
3350 support.tbody = !div.getElementsByTagName("tbody").length;
3351
3352 // Make sure that link elements get serialized correctly by innerHTML
3353 // This requires a wrapper element in IE
3354 support.htmlSerialize = !!div.getElementsByTagName("link").length;
3355
3356 // Get the style information from getAttribute
3357 // (IE uses .cssText instead)
3358 support.style = /top/.test( a.getAttribute("style") );
3359
3360 // Make sure that URLs aren't manipulated
3361 // (IE normalizes it by default)
3362 support.hrefNormalized = a.getAttribute("href") === "/a";
3363
3364 // Make sure that element opacity exists
3365 // (IE uses filter instead)
3366 // Use a regex to work around a WebKit issue. See #5145
3367 support.opacity = /^0.5/.test( a.style.opacity );
3368
3369 // Verify style float existence
3370 // (IE uses styleFloat instead of cssFloat)
3371 support.cssFloat = !!a.style.cssFloat;
3372
3373 // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
3374 support.checkOn = !!input.value;
3375
3376 // Make sure that a selected-by-default option has a working selected property.
3377 // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
3378 support.optSelected = opt.selected;
3379
3380 // Tests for enctype support on a form (#6743)
3381 support.enctype = !!document.createElement("form").enctype;
3382
3383 // Makes sure cloning an html5 element does not cause problems
3384 // Where outerHTML is undefined, this still works
3385 support.html5Clone = document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>";
3386
3387 // Will be defined later
3388 support.inlineBlockNeedsLayout = false;
3389 support.shrinkWrapBlocks = false;
3390 support.pixelPosition = false;
3391 support.deleteExpando = true;
3392 support.noCloneEvent = true;
3393 support.reliableMarginRight = true;
3394 support.boxSizingReliable = true;
3395
3396 // Make sure checked status is properly cloned
3397 input.checked = true;
3398 support.noCloneChecked = input.cloneNode( true ).checked;
3399
3400 // Make sure that the options inside disabled selects aren't marked as disabled
3401 // (WebKit marks them as disabled)
3402 select.disabled = true;
3403 support.optDisabled = !opt.disabled;
3404
3405 // Support: IE<9
3406 try {
3407 delete div.test;
3408 } catch( e ) {
3409 support.deleteExpando = false;
3410 }
3411
3412 // Check if we can trust getAttribute("value")
3413 input = document.createElement("input");
3414 input.setAttribute( "value", "" );
3415 support.input = input.getAttribute( "value" ) === "";
3416
3417 // Check if an input maintains its value after becoming a radio
3418 input.value = "t";
3419 input.setAttribute( "type", "radio" );
3420 support.radioValue = input.value === "t";
3421
3422 // #11217 - WebKit loses check when the name is after the checked attribute
3423 input.setAttribute( "checked", "t" );
3424 input.setAttribute( "name", "t" );
3425
3426 fragment = document.createDocumentFragment();
3427 fragment.appendChild( input );
3428
3429 // Check if a disconnected checkbox will retain its checked
3430 // value of true after appended to the DOM (IE6/7)
3431 support.appendChecked = input.checked;
3432
3433 // WebKit doesn't clone checked state correctly in fragments
3434 support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
3435
3436 // Support: IE<9
3437 // Opera does not clone events (and typeof div.attachEvent === undefined).
3438 // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
3439 if ( div.attachEvent ) {
3440 div.attachEvent( "onclick", function() {
3441 support.noCloneEvent = false;
3442 });
3443
3444 div.cloneNode( true ).click();
3445 }
3446
3447 // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
3448 // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
3449 for ( i in { submit: true, change: true, focusin: true }) {
3450 div.setAttribute( eventName = "on" + i, "t" );
3451
3452 support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
3453 }
3454
3455 div.style.backgroundClip = "content-box";
3456 div.cloneNode( true ).style.backgroundClip = "";
3457 support.clearCloneStyle = div.style.backgroundClip === "content-box";
3458
3459 // Support: IE<9
3460 // Iteration over object's inherited properties before its own.
3461 for ( i in jQuery( support ) ) {
3462 break;
3463 }
3464 support.ownLast = i !== "0";
3465
3466 // Run tests that need a body at doc ready
3467 jQuery(function() {
3468 var container, marginDiv, tds,
3469 divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
3470 body = document.getElementsByTagName("body")[0];
3471
3472 if ( !body ) {
3473 // Return for frameset docs that don't have a body
3474 return;
3475 }
3476
3477 container = document.createElement("div");
3478 container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
3479
3480 body.appendChild( container ).appendChild( div );
3481
3482 // Support: IE8
3483 // Check if table cells still have offsetWidth/Height when they are set
3484 // to display:none and there are still other visible table cells in a
3485 // table row; if so, offsetWidth/Height are not reliable for use when
3486 // determining if an element has been hidden directly using
3487 // display:none (it is still safe to use offsets if a parent element is
3488 // hidden; don safety goggles and see bug #4512 for more information).
3489 div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
3490 tds = div.getElementsByTagName("td");
3491 tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
3492 isSupported = ( tds[ 0 ].offsetHeight === 0 );
3493
3494 tds[ 0 ].style.display = "";
3495 tds[ 1 ].style.display = "none";
3496
3497 // Support: IE8
3498 // Check if empty table cells still have offsetWidth/Height
3499 support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
3500
3501 // Check box-sizing and margin behavior.
3502 div.innerHTML = "";
3503 div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
3504
3505 // Workaround failing boxSizing test due to offsetWidth returning wrong value
3506 // with some non-1 values of body zoom, ticket #13543
3507 jQuery.swap( body, body.style.zoom != null ? { zoom: 1 } : {}, function() {
3508 support.boxSizing = div.offsetWidth === 4;
3509 });
3510
3511 // Use window.getComputedStyle because jsdom on node.js will break without it.
3512 if ( window.getComputedStyle ) {
3513 support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
3514 support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
3515
3516 // Check if div with explicit width and no margin-right incorrectly
3517 // gets computed margin-right based on width of container. (#3333)
3518 // Fails in WebKit before Feb 2011 nightlies
3519 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
3520 marginDiv = div.appendChild( document.createElement("div") );
3521 marginDiv.style.cssText = div.style.cssText = divReset;
3522 marginDiv.style.marginRight = marginDiv.style.width = "0";
3523 div.style.width = "1px";
3524
3525 support.reliableMarginRight =
3526 !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
3527 }
3528
3529 if ( typeof div.style.zoom !== core_strundefined ) {
3530 // Support: IE<8
3531 // Check if natively block-level elements act like inline-block
3532 // elements when setting their display to 'inline' and giving
3533 // them layout
3534 div.innerHTML = "";
3535 div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
3536 support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
3537
3538 // Support: IE6
3539 // Check if elements with layout shrink-wrap their children
3540 div.style.display = "block";
3541 div.innerHTML = "<div></div>";
3542 div.firstChild.style.width = "5px";
3543 support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
3544
3545 if ( support.inlineBlockNeedsLayout ) {
3546 // Prevent IE 6 from affecting layout for positioned elements #11048
3547 // Prevent IE from shrinking the body in IE 7 mode #12869
3548 // Support: IE<8
3549 body.style.zoom = 1;
3550 }
3551 }
3552
3553 body.removeChild( container );
3554
3555 // Null elements to avoid leaks in IE
3556 container = div = tds = marginDiv = null;
3557 });
3558
3559 // Null elements to avoid leaks in IE
3560 all = select = fragment = opt = a = input = null;
3561
3562 return support;
3563})({});
3564
3565var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
3566 rmultiDash = /([A-Z])/g;
3567
3568function internalData( elem, name, data, pvt /* Internal Use Only */ ){
3569 if ( !jQuery.acceptData( elem ) ) {
3570 return;
3571 }
3572
3573 var ret, thisCache,
3574 internalKey = jQuery.expando,
3575
3576 // We have to handle DOM nodes and JS objects differently because IE6-7
3577 // can't GC object references properly across the DOM-JS boundary
3578 isNode = elem.nodeType,
3579
3580 // Only DOM nodes need the global jQuery cache; JS object data is
3581 // attached directly to the object so GC can occur automatically
3582 cache = isNode ? jQuery.cache : elem,
3583
3584 // Only defining an ID for JS objects if its cache already exists allows
3585 // the code to shortcut on the same path as a DOM node with no cache
3586 id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
3587
3588 // Avoid doing any more work than we need to when trying to get data on an
3589 // object that has no data at all
3590 if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
3591 return;
3592 }
3593
3594 if ( !id ) {
3595 // Only DOM nodes need a new unique ID for each element since their data
3596 // ends up in the global cache
3597 if ( isNode ) {
3598 id = elem[ internalKey ] = core_deletedIds.pop() || jQuery.guid++;
3599 } else {
3600 id = internalKey;
3601 }
3602 }
3603
3604 if ( !cache[ id ] ) {
3605 // Avoid exposing jQuery metadata on plain JS objects when the object
3606 // is serialized using JSON.stringify
3607 cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
3608 }
3609
3610 // An object can be passed to jQuery.data instead of a key/value pair; this gets
3611 // shallow copied over onto the existing cache
3612 if ( typeof name === "object" || typeof name === "function" ) {
3613 if ( pvt ) {
3614 cache[ id ] = jQuery.extend( cache[ id ], name );
3615 } else {
3616 cache[ id ].data = jQuery.extend( cache[ id ].data, name );
3617 }
3618 }
3619
3620 thisCache = cache[ id ];
3621
3622 // jQuery data() is stored in a separate object inside the object's internal data
3623 // cache in order to avoid key collisions between internal data and user-defined
3624 // data.
3625 if ( !pvt ) {
3626 if ( !thisCache.data ) {
3627 thisCache.data = {};
3628 }
3629
3630 thisCache = thisCache.data;
3631 }
3632
3633 if ( data !== undefined ) {
3634 thisCache[ jQuery.camelCase( name ) ] = data;
3635 }
3636
3637 // Check for both converted-to-camel and non-converted data property names
3638 // If a data property was specified
3639 if ( typeof name === "string" ) {
3640
3641 // First Try to find as-is property data
3642 ret = thisCache[ name ];
3643
3644 // Test for null|undefined property data
3645 if ( ret == null ) {
3646
3647 // Try to find the camelCased property
3648 ret = thisCache[ jQuery.camelCase( name ) ];
3649 }
3650 } else {
3651 ret = thisCache;
3652 }
3653
3654 return ret;
3655}
3656
3657function internalRemoveData( elem, name, pvt ) {
3658 if ( !jQuery.acceptData( elem ) ) {
3659 return;
3660 }
3661
3662 var thisCache, i,
3663 isNode = elem.nodeType,
3664
3665 // See jQuery.data for more information
3666 cache = isNode ? jQuery.cache : elem,
3667 id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
3668
3669 // If there is already no cache entry for this object, there is no
3670 // purpose in continuing
3671 if ( !cache[ id ] ) {
3672 return;
3673 }
3674
3675 if ( name ) {
3676
3677 thisCache = pvt ? cache[ id ] : cache[ id ].data;
3678
3679 if ( thisCache ) {
3680
3681 // Support array or space separated string names for data keys
3682 if ( !jQuery.isArray( name ) ) {
3683
3684 // try the string as a key before any manipulation
3685 if ( name in thisCache ) {
3686 name = [ name ];
3687 } else {
3688
3689 // split the camel cased version by spaces unless a key with the spaces exists
3690 name = jQuery.camelCase( name );
3691 if ( name in thisCache ) {
3692 name = [ name ];
3693 } else {
3694 name = name.split(" ");
3695 }
3696 }
3697 } else {
3698 // If "name" is an array of keys...
3699 // When data is initially created, via ("key", "val") signature,
3700 // keys will be converted to camelCase.
3701 // Since there is no way to tell _how_ a key was added, remove
3702 // both plain key and camelCase key. #12786
3703 // This will only penalize the array argument path.
3704 name = name.concat( jQuery.map( name, jQuery.camelCase ) );
3705 }
3706
3707 i = name.length;
3708 while ( i-- ) {
3709 delete thisCache[ name[i] ];
3710 }
3711
3712 // If there is no data left in the cache, we want to continue
3713 // and let the cache object itself get destroyed
3714 if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
3715 return;
3716 }
3717 }
3718 }
3719
3720 // See jQuery.data for more information
3721 if ( !pvt ) {
3722 delete cache[ id ].data;
3723
3724 // Don't destroy the parent cache unless the internal data object
3725 // had been the only thing left in it
3726 if ( !isEmptyDataObject( cache[ id ] ) ) {
3727 return;
3728 }
3729 }
3730
3731 // Destroy the cache
3732 if ( isNode ) {
3733 jQuery.cleanData( [ elem ], true );
3734
3735 // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
3736 /* jshint eqeqeq: false */
3737 } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
3738 /* jshint eqeqeq: true */
3739 delete cache[ id ];
3740
3741 // When all else fails, null
3742 } else {
3743 cache[ id ] = null;
3744 }
3745}
3746
3747jQuery.extend({
3748 cache: {},
3749
3750 // The following elements throw uncatchable exceptions if you
3751 // attempt to add expando properties to them.
3752 noData: {
3753 "applet": true,
3754 "embed": true,
3755 // Ban all objects except for Flash (which handle expandos)
3756 "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
3757 },
3758
3759 hasData: function( elem ) {
3760 elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
3761 return !!elem && !isEmptyDataObject( elem );
3762 },
3763
3764 data: function( elem, name, data ) {
3765 return internalData( elem, name, data );
3766 },
3767
3768 removeData: function( elem, name ) {
3769 return internalRemoveData( elem, name );
3770 },
3771
3772 // For internal use only.
3773 _data: function( elem, name, data ) {
3774 return internalData( elem, name, data, true );
3775 },
3776
3777 _removeData: function( elem, name ) {
3778 return internalRemoveData( elem, name, true );
3779 },
3780
3781 // A method for determining if a DOM node can handle the data expando
3782 acceptData: function( elem ) {
3783 // Do not set data on non-element because it will not be cleared (#8335).
3784 if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
3785 return false;
3786 }
3787
3788 var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
3789
3790 // nodes accept data unless otherwise specified; rejection can be conditional
3791 return !noData || noData !== true && elem.getAttribute("classid") === noData;
3792 }
3793});
3794
3795jQuery.fn.extend({
3796 data: function( key, value ) {
3797 var attrs, name,
3798 data = null,
3799 i = 0,
3800 elem = this[0];
3801
3802 // Special expections of .data basically thwart jQuery.access,
3803 // so implement the relevant behavior ourselves
3804
3805 // Gets all values
3806 if ( key === undefined ) {
3807 if ( this.length ) {
3808 data = jQuery.data( elem );
3809
3810 if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
3811 attrs = elem.attributes;
3812 for ( ; i < attrs.length; i++ ) {
3813 name = attrs[i].name;
3814
3815 if ( name.indexOf("data-") === 0 ) {
3816 name = jQuery.camelCase( name.slice(5) );
3817
3818 dataAttr( elem, name, data[ name ] );
3819 }
3820 }
3821 jQuery._data( elem, "parsedAttrs", true );
3822 }
3823 }
3824
3825 return data;
3826 }
3827
3828 // Sets multiple values
3829 if ( typeof key === "object" ) {
3830 return this.each(function() {
3831 jQuery.data( this, key );
3832 });
3833 }
3834
3835 return arguments.length > 1 ?
3836
3837 // Sets one value
3838 this.each(function() {
3839 jQuery.data( this, key, value );
3840 }) :
3841
3842 // Gets one value
3843 // Try to fetch any internally stored data first
3844 elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
3845 },
3846
3847 removeData: function( key ) {
3848 return this.each(function() {
3849 jQuery.removeData( this, key );
3850 });
3851 }
3852});
3853
3854function dataAttr( elem, key, data ) {
3855 // If nothing was found internally, try to fetch any
3856 // data from the HTML5 data-* attribute
3857 if ( data === undefined && elem.nodeType === 1 ) {
3858
3859 var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3860
3861 data = elem.getAttribute( name );
3862
3863 if ( typeof data === "string" ) {
3864 try {
3865 data = data === "true" ? true :
3866 data === "false" ? false :
3867 data === "null" ? null :
3868 // Only convert to a number if it doesn't change the string
3869 +data + "" === data ? +data :
3870 rbrace.test( data ) ? jQuery.parseJSON( data ) :
3871 data;
3872 } catch( e ) {}
3873
3874 // Make sure we set the data so it isn't changed later
3875 jQuery.data( elem, key, data );
3876
3877 } else {
3878 data = undefined;
3879 }
3880 }
3881
3882 return data;
3883}
3884
3885// checks a cache object for emptiness
3886function isEmptyDataObject( obj ) {
3887 var name;
3888 for ( name in obj ) {
3889
3890 // if the public data object is empty, the private is still empty
3891 if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
3892 continue;
3893 }
3894 if ( name !== "toJSON" ) {
3895 return false;
3896 }
3897 }
3898
3899 return true;
3900}
3901jQuery.extend({
3902 queue: function( elem, type, data ) {
3903 var queue;
3904
3905 if ( elem ) {
3906 type = ( type || "fx" ) + "queue";
3907 queue = jQuery._data( elem, type );
3908
3909 // Speed up dequeue by getting out quickly if this is just a lookup
3910 if ( data ) {
3911 if ( !queue || jQuery.isArray(data) ) {
3912 queue = jQuery._data( elem, type, jQuery.makeArray(data) );
3913 } else {
3914 queue.push( data );
3915 }
3916 }
3917 return queue || [];
3918 }
3919 },
3920
3921 dequeue: function( elem, type ) {
3922 type = type || "fx";
3923
3924 var queue = jQuery.queue( elem, type ),
3925 startLength = queue.length,
3926 fn = queue.shift(),
3927 hooks = jQuery._queueHooks( elem, type ),
3928 next = function() {
3929 jQuery.dequeue( elem, type );
3930 };
3931
3932 // If the fx queue is dequeued, always remove the progress sentinel
3933 if ( fn === "inprogress" ) {
3934 fn = queue.shift();
3935 startLength--;
3936 }
3937
3938 if ( fn ) {
3939
3940 // Add a progress sentinel to prevent the fx queue from being
3941 // automatically dequeued
3942 if ( type === "fx" ) {
3943 queue.unshift( "inprogress" );
3944 }
3945
3946 // clear up the last queue stop function
3947 delete hooks.stop;
3948 fn.call( elem, next, hooks );
3949 }
3950
3951 if ( !startLength && hooks ) {
3952 hooks.empty.fire();
3953 }
3954 },
3955
3956 // not intended for public consumption - generates a queueHooks object, or returns the current one
3957 _queueHooks: function( elem, type ) {
3958 var key = type + "queueHooks";
3959 return jQuery._data( elem, key ) || jQuery._data( elem, key, {
3960 empty: jQuery.Callbacks("once memory").add(function() {
3961 jQuery._removeData( elem, type + "queue" );
3962 jQuery._removeData( elem, key );
3963 })
3964 });
3965 }
3966});
3967
3968jQuery.fn.extend({
3969 queue: function( type, data ) {
3970 var setter = 2;
3971
3972 if ( typeof type !== "string" ) {
3973 data = type;
3974 type = "fx";
3975 setter--;
3976 }
3977
3978 if ( arguments.length < setter ) {
3979 return jQuery.queue( this[0], type );
3980 }
3981
3982 return data === undefined ?
3983 this :
3984 this.each(function() {
3985 var queue = jQuery.queue( this, type, data );
3986
3987 // ensure a hooks for this queue
3988 jQuery._queueHooks( this, type );
3989
3990 if ( type === "fx" && queue[0] !== "inprogress" ) {
3991 jQuery.dequeue( this, type );
3992 }
3993 });
3994 },
3995 dequeue: function( type ) {
3996 return this.each(function() {
3997 jQuery.dequeue( this, type );
3998 });
3999 },
4000 // Based off of the plugin by Clint Helfers, with permission.
4001 // http://blindsignals.com/index.php/2009/07/jquery-delay/
4002 delay: function( time, type ) {
4003 time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
4004 type = type || "fx";
4005
4006 return this.queue( type, function( next, hooks ) {
4007 var timeout = setTimeout( next, time );
4008 hooks.stop = function() {
4009 clearTimeout( timeout );
4010 };
4011 });
4012 },
4013 clearQueue: function( type ) {
4014 return this.queue( type || "fx", [] );
4015 },
4016 // Get a promise resolved when queues of a certain type
4017 // are emptied (fx is the type by default)
4018 promise: function( type, obj ) {
4019 var tmp,
4020 count = 1,
4021 defer = jQuery.Deferred(),
4022 elements = this,
4023 i = this.length,
4024 resolve = function() {
4025 if ( !( --count ) ) {
4026 defer.resolveWith( elements, [ elements ] );
4027 }
4028 };
4029
4030 if ( typeof type !== "string" ) {
4031 obj = type;
4032 type = undefined;
4033 }
4034 type = type || "fx";
4035
4036 while( i-- ) {
4037 tmp = jQuery._data( elements[ i ], type + "queueHooks" );
4038 if ( tmp && tmp.empty ) {
4039 count++;
4040 tmp.empty.add( resolve );
4041 }
4042 }
4043 resolve();
4044 return defer.promise( obj );
4045 }
4046});
4047var nodeHook, boolHook,
4048 rclass = /[\t\r\n\f]/g,
4049 rreturn = /\r/g,
4050 rfocusable = /^(?:input|select|textarea|button|object)$/i,
4051 rclickable = /^(?:a|area)$/i,
4052 ruseDefault = /^(?:checked|selected)$/i,
4053 getSetAttribute = jQuery.support.getSetAttribute,
4054 getSetInput = jQuery.support.input;
4055
4056jQuery.fn.extend({
4057 attr: function( name, value ) {
4058 return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
4059 },
4060
4061 removeAttr: function( name ) {
4062 return this.each(function() {
4063 jQuery.removeAttr( this, name );
4064 });
4065 },
4066
4067 prop: function( name, value ) {
4068 return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
4069 },
4070
4071 removeProp: function( name ) {
4072 name = jQuery.propFix[ name ] || name;
4073 return this.each(function() {
4074 // try/catch handles cases where IE balks (such as removing a property on window)
4075 try {
4076 this[ name ] = undefined;
4077 delete this[ name ];
4078 } catch( e ) {}
4079 });
4080 },
4081
4082 addClass: function( value ) {
4083 var classes, elem, cur, clazz, j,
4084 i = 0,
4085 len = this.length,
4086 proceed = typeof value === "string" && value;
4087
4088 if ( jQuery.isFunction( value ) ) {
4089 return this.each(function( j ) {
4090 jQuery( this ).addClass( value.call( this, j, this.className ) );
4091 });
4092 }
4093
4094 if ( proceed ) {
4095 // The disjunction here is for better compressibility (see removeClass)
4096 classes = ( value || "" ).match( core_rnotwhite ) || [];
4097
4098 for ( ; i < len; i++ ) {
4099 elem = this[ i ];
4100 cur = elem.nodeType === 1 && ( elem.className ?
4101 ( " " + elem.className + " " ).replace( rclass, " " ) :
4102 " "
4103 );
4104
4105 if ( cur ) {
4106 j = 0;
4107 while ( (clazz = classes[j++]) ) {
4108 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
4109 cur += clazz + " ";
4110 }
4111 }
4112 elem.className = jQuery.trim( cur );
4113
4114 }
4115 }
4116 }
4117
4118 return this;
4119 },
4120
4121 removeClass: function( value ) {
4122 var classes, elem, cur, clazz, j,
4123 i = 0,
4124 len = this.length,
4125 proceed = arguments.length === 0 || typeof value === "string" && value;
4126
4127 if ( jQuery.isFunction( value ) ) {
4128 return this.each(function( j ) {
4129 jQuery( this ).removeClass( value.call( this, j, this.className ) );
4130 });
4131 }
4132 if ( proceed ) {
4133 classes = ( value || "" ).match( core_rnotwhite ) || [];
4134
4135 for ( ; i < len; i++ ) {
4136 elem = this[ i ];
4137 // This expression is here for better compressibility (see addClass)
4138 cur = elem.nodeType === 1 && ( elem.className ?
4139 ( " " + elem.className + " " ).replace( rclass, " " ) :
4140 ""
4141 );
4142
4143 if ( cur ) {
4144 j = 0;
4145 while ( (clazz = classes[j++]) ) {
4146 // Remove *all* instances
4147 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
4148 cur = cur.replace( " " + clazz + " ", " " );
4149 }
4150 }
4151 elem.className = value ? jQuery.trim( cur ) : "";
4152 }
4153 }
4154 }
4155
4156 return this;
4157 },
4158
4159 toggleClass: function( value, stateVal ) {
4160 var type = typeof value;
4161
4162 if ( typeof stateVal === "boolean" && type === "string" ) {
4163 return stateVal ? this.addClass( value ) : this.removeClass( value );
4164 }
4165
4166 if ( jQuery.isFunction( value ) ) {
4167 return this.each(function( i ) {
4168 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
4169 });
4170 }
4171
4172 return this.each(function() {
4173 if ( type === "string" ) {
4174 // toggle individual class names
4175 var className,
4176 i = 0,
4177 self = jQuery( this ),
4178 classNames = value.match( core_rnotwhite ) || [];
4179
4180 while ( (className = classNames[ i++ ]) ) {
4181 // check each className given, space separated list
4182 if ( self.hasClass( className ) ) {
4183 self.removeClass( className );
4184 } else {
4185 self.addClass( className );
4186 }
4187 }
4188
4189 // Toggle whole class name
4190 } else if ( type === core_strundefined || type === "boolean" ) {
4191 if ( this.className ) {
4192 // store className if set
4193 jQuery._data( this, "__className__", this.className );
4194 }
4195
4196 // If the element has a class name or if we're passed "false",
4197 // then remove the whole classname (if there was one, the above saved it).
4198 // Otherwise bring back whatever was previously saved (if anything),
4199 // falling back to the empty string if nothing was stored.
4200 this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
4201 }
4202 });
4203 },
4204
4205 hasClass: function( selector ) {
4206 var className = " " + selector + " ",
4207 i = 0,
4208 l = this.length;
4209 for ( ; i < l; i++ ) {
4210 if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
4211 return true;
4212 }
4213 }
4214
4215 return false;
4216 },
4217
4218 val: function( value ) {
4219 var ret, hooks, isFunction,
4220 elem = this[0];
4221
4222 if ( !arguments.length ) {
4223 if ( elem ) {
4224 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
4225
4226 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
4227 return ret;
4228 }
4229
4230 ret = elem.value;
4231
4232 return typeof ret === "string" ?
4233 // handle most common string cases
4234 ret.replace(rreturn, "") :
4235 // handle cases where value is null/undef or number
4236 ret == null ? "" : ret;
4237 }
4238
4239 return;
4240 }
4241
4242 isFunction = jQuery.isFunction( value );
4243
4244 return this.each(function( i ) {
4245 var val;
4246
4247 if ( this.nodeType !== 1 ) {
4248 return;
4249 }
4250
4251 if ( isFunction ) {
4252 val = value.call( this, i, jQuery( this ).val() );
4253 } else {
4254 val = value;
4255 }
4256
4257 // Treat null/undefined as ""; convert numbers to string
4258 if ( val == null ) {
4259 val = "";
4260 } else if ( typeof val === "number" ) {
4261 val += "";
4262 } else if ( jQuery.isArray( val ) ) {
4263 val = jQuery.map(val, function ( value ) {
4264 return value == null ? "" : value + "";
4265 });
4266 }
4267
4268 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
4269
4270 // If set returns undefined, fall back to normal setting
4271 if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
4272 this.value = val;
4273 }
4274 });
4275 }
4276});
4277
4278jQuery.extend({
4279 valHooks: {
4280 option: {
4281 get: function( elem ) {
4282 // Use proper attribute retrieval(#6932, #12072)
4283 var val = jQuery.find.attr( elem, "value" );
4284 return val != null ?
4285 val :
4286 elem.text;
4287 }
4288 },
4289 select: {
4290 get: function( elem ) {
4291 var value, option,
4292 options = elem.options,
4293 index = elem.selectedIndex,
4294 one = elem.type === "select-one" || index < 0,
4295 values = one ? null : [],
4296 max = one ? index + 1 : options.length,
4297 i = index < 0 ?
4298 max :
4299 one ? index : 0;
4300
4301 // Loop through all the selected options
4302 for ( ; i < max; i++ ) {
4303 option = options[ i ];
4304
4305 // oldIE doesn't update selected after form reset (#2551)
4306 if ( ( option.selected || i === index ) &&
4307 // Don't return options that are disabled or in a disabled optgroup
4308 ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
4309 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
4310
4311 // Get the specific value for the option
4312 value = jQuery( option ).val();
4313
4314 // We don't need an array for one selects
4315 if ( one ) {
4316 return value;
4317 }
4318
4319 // Multi-Selects return an array
4320 values.push( value );
4321 }
4322 }
4323
4324 return values;
4325 },
4326
4327 set: function( elem, value ) {
4328 var optionSet, option,
4329 options = elem.options,
4330 values = jQuery.makeArray( value ),
4331 i = options.length;
4332
4333 while ( i-- ) {
4334 option = options[ i ];
4335 if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {
4336 optionSet = true;
4337 }
4338 }
4339
4340 // force browsers to behave consistently when non-matching value is set
4341 if ( !optionSet ) {
4342 elem.selectedIndex = -1;
4343 }
4344 return values;
4345 }
4346 }
4347 },
4348
4349 attr: function( elem, name, value ) {
4350 var hooks, ret,
4351 nType = elem.nodeType;
4352
4353 // don't get/set attributes on text, comment and attribute nodes
4354 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4355 return;
4356 }
4357
4358 // Fallback to prop when attributes are not supported
4359 if ( typeof elem.getAttribute === core_strundefined ) {
4360 return jQuery.prop( elem, name, value );
4361 }
4362
4363 // All attributes are lowercase
4364 // Grab necessary hook if one is defined
4365 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
4366 name = name.toLowerCase();
4367 hooks = jQuery.attrHooks[ name ] ||
4368 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
4369 }
4370
4371 if ( value !== undefined ) {
4372
4373 if ( value === null ) {
4374 jQuery.removeAttr( elem, name );
4375
4376 } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
4377 return ret;
4378
4379 } else {
4380 elem.setAttribute( name, value + "" );
4381 return value;
4382 }
4383
4384 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
4385 return ret;
4386
4387 } else {
4388 ret = jQuery.find.attr( elem, name );
4389
4390 // Non-existent attributes return null, we normalize to undefined
4391 return ret == null ?
4392 undefined :
4393 ret;
4394 }
4395 },
4396
4397 removeAttr: function( elem, value ) {
4398 var name, propName,
4399 i = 0,
4400 attrNames = value && value.match( core_rnotwhite );
4401
4402 if ( attrNames && elem.nodeType === 1 ) {
4403 while ( (name = attrNames[i++]) ) {
4404 propName = jQuery.propFix[ name ] || name;
4405
4406 // Boolean attributes get special treatment (#10870)
4407 if ( jQuery.expr.match.bool.test( name ) ) {
4408 // Set corresponding property to false
4409 if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4410 elem[ propName ] = false;
4411 // Support: IE<9
4412 // Also clear defaultChecked/defaultSelected (if appropriate)
4413 } else {
4414 elem[ jQuery.camelCase( "default-" + name ) ] =
4415 elem[ propName ] = false;
4416 }
4417
4418 // See #9699 for explanation of this approach (setting first, then removal)
4419 } else {
4420 jQuery.attr( elem, name, "" );
4421 }
4422
4423 elem.removeAttribute( getSetAttribute ? name : propName );
4424 }
4425 }
4426 },
4427
4428 attrHooks: {
4429 type: {
4430 set: function( elem, value ) {
4431 if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
4432 // Setting the type on a radio button after the value resets the value in IE6-9
4433 // Reset value to default in case type is set after value during creation
4434 var val = elem.value;
4435 elem.setAttribute( "type", value );
4436 if ( val ) {
4437 elem.value = val;
4438 }
4439 return value;
4440 }
4441 }
4442 }
4443 },
4444
4445 propFix: {
4446 "for": "htmlFor",
4447 "class": "className"
4448 },
4449
4450 prop: function( elem, name, value ) {
4451 var ret, hooks, notxml,
4452 nType = elem.nodeType;
4453
4454 // don't get/set properties on text, comment and attribute nodes
4455 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
4456 return;
4457 }
4458
4459 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
4460
4461 if ( notxml ) {
4462 // Fix name and attach hooks
4463 name = jQuery.propFix[ name ] || name;
4464 hooks = jQuery.propHooks[ name ];
4465 }
4466
4467 if ( value !== undefined ) {
4468 return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
4469 ret :
4470 ( elem[ name ] = value );
4471
4472 } else {
4473 return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
4474 ret :
4475 elem[ name ];
4476 }
4477 },
4478
4479 propHooks: {
4480 tabIndex: {
4481 get: function( elem ) {
4482 // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
4483 // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
4484 // Use proper attribute retrieval(#12072)
4485 var tabindex = jQuery.find.attr( elem, "tabindex" );
4486
4487 return tabindex ?
4488 parseInt( tabindex, 10 ) :
4489 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
4490 0 :
4491 -1;
4492 }
4493 }
4494 }
4495});
4496
4497// Hooks for boolean attributes
4498boolHook = {
4499 set: function( elem, value, name ) {
4500 if ( value === false ) {
4501 // Remove boolean attributes when set to false
4502 jQuery.removeAttr( elem, name );
4503 } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
4504 // IE<8 needs the *property* name
4505 elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
4506
4507 // Use defaultChecked and defaultSelected for oldIE
4508 } else {
4509 elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
4510 }
4511
4512 return name;
4513 }
4514};
4515jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
4516 var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;
4517
4518 jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
4519 function( elem, name, isXML ) {
4520 var fn = jQuery.expr.attrHandle[ name ],
4521 ret = isXML ?
4522 undefined :
4523 /* jshint eqeqeq: false */
4524 (jQuery.expr.attrHandle[ name ] = undefined) !=
4525 getter( elem, name, isXML ) ?
4526
4527 name.toLowerCase() :
4528 null;
4529 jQuery.expr.attrHandle[ name ] = fn;
4530 return ret;
4531 } :
4532 function( elem, name, isXML ) {
4533 return isXML ?
4534 undefined :
4535 elem[ jQuery.camelCase( "default-" + name ) ] ?
4536 name.toLowerCase() :
4537 null;
4538 };
4539});
4540
4541// fix oldIE attroperties
4542if ( !getSetInput || !getSetAttribute ) {
4543 jQuery.attrHooks.value = {
4544 set: function( elem, value, name ) {
4545 if ( jQuery.nodeName( elem, "input" ) ) {
4546 // Does not return so that setAttribute is also used
4547 elem.defaultValue = value;
4548 } else {
4549 // Use nodeHook if defined (#1954); otherwise setAttribute is fine
4550 return nodeHook && nodeHook.set( elem, value, name );
4551 }
4552 }
4553 };
4554}
4555
4556// IE6/7 do not support getting/setting some attributes with get/setAttribute
4557if ( !getSetAttribute ) {
4558
4559 // Use this for any attribute in IE6/7
4560 // This fixes almost every IE6/7 issue
4561 nodeHook = {
4562 set: function( elem, value, name ) {
4563 // Set the existing or create a new attribute node
4564 var ret = elem.getAttributeNode( name );
4565 if ( !ret ) {
4566 elem.setAttributeNode(
4567 (ret = elem.ownerDocument.createAttribute( name ))
4568 );
4569 }
4570
4571 ret.value = value += "";
4572
4573 // Break association with cloned elements by also using setAttribute (#9646)
4574 return name === "value" || value === elem.getAttribute( name ) ?
4575 value :
4576 undefined;
4577 }
4578 };
4579 jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
4580 // Some attributes are constructed with empty-string values when not defined
4581 function( elem, name, isXML ) {
4582 var ret;
4583 return isXML ?
4584 undefined :
4585 (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
4586 ret.value :
4587 null;
4588 };
4589 jQuery.valHooks.button = {
4590 get: function( elem, name ) {
4591 var ret = elem.getAttributeNode( name );
4592 return ret && ret.specified ?
4593 ret.value :
4594 undefined;
4595 },
4596 set: nodeHook.set
4597 };
4598
4599 // Set contenteditable to false on removals(#10429)
4600 // Setting to empty string throws an error as an invalid value
4601 jQuery.attrHooks.contenteditable = {
4602 set: function( elem, value, name ) {
4603 nodeHook.set( elem, value === "" ? false : value, name );
4604 }
4605 };
4606
4607 // Set width and height to auto instead of 0 on empty string( Bug #8150 )
4608 // This is for removals
4609 jQuery.each([ "width", "height" ], function( i, name ) {
4610 jQuery.attrHooks[ name ] = {
4611 set: function( elem, value ) {
4612 if ( value === "" ) {
4613 elem.setAttribute( name, "auto" );
4614 return value;
4615 }
4616 }
4617 };
4618 });
4619}
4620
4621
4622// Some attributes require a special call on IE
4623// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
4624if ( !jQuery.support.hrefNormalized ) {
4625 // href/src property should get the full normalized URL (#10299/#12915)
4626 jQuery.each([ "href", "src" ], function( i, name ) {
4627 jQuery.propHooks[ name ] = {
4628 get: function( elem ) {
4629 return elem.getAttribute( name, 4 );
4630 }
4631 };
4632 });
4633}
4634
4635if ( !jQuery.support.style ) {
4636 jQuery.attrHooks.style = {
4637 get: function( elem ) {
4638 // Return undefined in the case of empty string
4639 // Note: IE uppercases css property names, but if we were to .toLowerCase()
4640 // .cssText, that would destroy case senstitivity in URL's, like in "background"
4641 return elem.style.cssText || undefined;
4642 },
4643 set: function( elem, value ) {
4644 return ( elem.style.cssText = value + "" );
4645 }
4646 };
4647}
4648
4649// Safari mis-reports the default selected property of an option
4650// Accessing the parent's selectedIndex property fixes it
4651if ( !jQuery.support.optSelected ) {
4652 jQuery.propHooks.selected = {
4653 get: function( elem ) {
4654 var parent = elem.parentNode;
4655
4656 if ( parent ) {
4657 parent.selectedIndex;
4658
4659 // Make sure that it also works with optgroups, see #5701
4660 if ( parent.parentNode ) {
4661 parent.parentNode.selectedIndex;
4662 }
4663 }
4664 return null;
4665 }
4666 };
4667}
4668
4669jQuery.each([
4670 "tabIndex",
4671 "readOnly",
4672 "maxLength",
4673 "cellSpacing",
4674 "cellPadding",
4675 "rowSpan",
4676 "colSpan",
4677 "useMap",
4678 "frameBorder",
4679 "contentEditable"
4680], function() {
4681 jQuery.propFix[ this.toLowerCase() ] = this;
4682});
4683
4684// IE6/7 call enctype encoding
4685if ( !jQuery.support.enctype ) {
4686 jQuery.propFix.enctype = "encoding";
4687}
4688
4689// Radios and checkboxes getter/setter
4690jQuery.each([ "radio", "checkbox" ], function() {
4691 jQuery.valHooks[ this ] = {
4692 set: function( elem, value ) {
4693 if ( jQuery.isArray( value ) ) {
4694 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
4695 }
4696 }
4697 };
4698 if ( !jQuery.support.checkOn ) {
4699 jQuery.valHooks[ this ].get = function( elem ) {
4700 // Support: Webkit
4701 // "" is returned instead of "on" if a value isn't specified
4702 return elem.getAttribute("value") === null ? "on" : elem.value;
4703 };
4704 }
4705});
4706var rformElems = /^(?:input|select|textarea)$/i,
4707 rkeyEvent = /^key/,
4708 rmouseEvent = /^(?:mouse|contextmenu)|click/,
4709 rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4710 rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4711
4712function returnTrue() {
4713 return true;
4714}
4715
4716function returnFalse() {
4717 return false;
4718}
4719
4720function safeActiveElement() {
4721 try {
4722 return document.activeElement;
4723 } catch ( err ) { }
4724}
4725
4726/*
4727 * Helper functions for managing events -- not part of the public interface.
4728 * Props to Dean Edwards' addEvent library for many of the ideas.
4729 */
4730jQuery.event = {
4731
4732 global: {},
4733
4734 add: function( elem, types, handler, data, selector ) {
4735 var tmp, events, t, handleObjIn,
4736 special, eventHandle, handleObj,
4737 handlers, type, namespaces, origType,
4738 elemData = jQuery._data( elem );
4739
4740 // Don't attach events to noData or text/comment nodes (but allow plain objects)
4741 if ( !elemData ) {
4742 return;
4743 }
4744
4745 // Caller can pass in an object of custom data in lieu of the handler
4746 if ( handler.handler ) {
4747 handleObjIn = handler;
4748 handler = handleObjIn.handler;
4749 selector = handleObjIn.selector;
4750 }
4751
4752 // Make sure that the handler has a unique ID, used to find/remove it later
4753 if ( !handler.guid ) {
4754 handler.guid = jQuery.guid++;
4755 }
4756
4757 // Init the element's event structure and main handler, if this is the first
4758 if ( !(events = elemData.events) ) {
4759 events = elemData.events = {};
4760 }
4761 if ( !(eventHandle = elemData.handle) ) {
4762 eventHandle = elemData.handle = function( e ) {
4763 // Discard the second event of a jQuery.event.trigger() and
4764 // when an event is called after a page has unloaded
4765 return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
4766 jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
4767 undefined;
4768 };
4769 // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
4770 eventHandle.elem = elem;
4771 }
4772
4773 // Handle multiple events separated by a space
4774 types = ( types || "" ).match( core_rnotwhite ) || [""];
4775 t = types.length;
4776 while ( t-- ) {
4777 tmp = rtypenamespace.exec( types[t] ) || [];
4778 type = origType = tmp[1];
4779 namespaces = ( tmp[2] || "" ).split( "." ).sort();
4780
4781 // There *must* be a type, no attaching namespace-only handlers
4782 if ( !type ) {
4783 continue;
4784 }
4785
4786 // If event changes its type, use the special event handlers for the changed type
4787 special = jQuery.event.special[ type ] || {};
4788
4789 // If selector defined, determine special event api type, otherwise given type
4790 type = ( selector ? special.delegateType : special.bindType ) || type;
4791
4792 // Update special based on newly reset type
4793 special = jQuery.event.special[ type ] || {};
4794
4795 // handleObj is passed to all event handlers
4796 handleObj = jQuery.extend({
4797 type: type,
4798 origType: origType,
4799 data: data,
4800 handler: handler,
4801 guid: handler.guid,
4802 selector: selector,
4803 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4804 namespace: namespaces.join(".")
4805 }, handleObjIn );
4806
4807 // Init the event handler queue if we're the first
4808 if ( !(handlers = events[ type ]) ) {
4809 handlers = events[ type ] = [];
4810 handlers.delegateCount = 0;
4811
4812 // Only use addEventListener/attachEvent if the special events handler returns false
4813 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4814 // Bind the global event handler to the element
4815 if ( elem.addEventListener ) {
4816 elem.addEventListener( type, eventHandle, false );
4817
4818 } else if ( elem.attachEvent ) {
4819 elem.attachEvent( "on" + type, eventHandle );
4820 }
4821 }
4822 }
4823
4824 if ( special.add ) {
4825 special.add.call( elem, handleObj );
4826
4827 if ( !handleObj.handler.guid ) {
4828 handleObj.handler.guid = handler.guid;
4829 }
4830 }
4831
4832 // Add to the element's handler list, delegates in front
4833 if ( selector ) {
4834 handlers.splice( handlers.delegateCount++, 0, handleObj );
4835 } else {
4836 handlers.push( handleObj );
4837 }
4838
4839 // Keep track of which events have ever been used, for event optimization
4840 jQuery.event.global[ type ] = true;
4841 }
4842
4843 // Nullify elem to prevent memory leaks in IE
4844 elem = null;
4845 },
4846
4847 // Detach an event or set of events from an element
4848 remove: function( elem, types, handler, selector, mappedTypes ) {
4849 var j, handleObj, tmp,
4850 origCount, t, events,
4851 special, handlers, type,
4852 namespaces, origType,
4853 elemData = jQuery.hasData( elem ) && jQuery._data( elem );
4854
4855 if ( !elemData || !(events = elemData.events) ) {
4856 return;
4857 }
4858
4859 // Once for each type.namespace in types; type may be omitted
4860 types = ( types || "" ).match( core_rnotwhite ) || [""];
4861 t = types.length;
4862 while ( t-- ) {
4863 tmp = rtypenamespace.exec( types[t] ) || [];
4864 type = origType = tmp[1];
4865 namespaces = ( tmp[2] || "" ).split( "." ).sort();
4866
4867 // Unbind all events (on this namespace, if provided) for the element
4868 if ( !type ) {
4869 for ( type in events ) {
4870 jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4871 }
4872 continue;
4873 }
4874
4875 special = jQuery.event.special[ type ] || {};
4876 type = ( selector ? special.delegateType : special.bindType ) || type;
4877 handlers = events[ type ] || [];
4878 tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4879
4880 // Remove matching events
4881 origCount = j = handlers.length;
4882 while ( j-- ) {
4883 handleObj = handlers[ j ];
4884
4885 if ( ( mappedTypes || origType === handleObj.origType ) &&
4886 ( !handler || handler.guid === handleObj.guid ) &&
4887 ( !tmp || tmp.test( handleObj.namespace ) ) &&
4888 ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4889 handlers.splice( j, 1 );
4890
4891 if ( handleObj.selector ) {
4892 handlers.delegateCount--;
4893 }
4894 if ( special.remove ) {
4895 special.remove.call( elem, handleObj );
4896 }
4897 }
4898 }
4899
4900 // Remove generic event handler if we removed something and no more handlers exist
4901 // (avoids potential for endless recursion during removal of special event handlers)
4902 if ( origCount && !handlers.length ) {
4903 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4904 jQuery.removeEvent( elem, type, elemData.handle );
4905 }
4906
4907 delete events[ type ];
4908 }
4909 }
4910
4911 // Remove the expando if it's no longer used
4912 if ( jQuery.isEmptyObject( events ) ) {
4913 delete elemData.handle;
4914
4915 // removeData also checks for emptiness and clears the expando if empty
4916 // so use it instead of delete
4917 jQuery._removeData( elem, "events" );
4918 }
4919 },
4920
4921 trigger: function( event, data, elem, onlyHandlers ) {
4922 var handle, ontype, cur,
4923 bubbleType, special, tmp, i,
4924 eventPath = [ elem || document ],
4925 type = core_hasOwn.call( event, "type" ) ? event.type : event,
4926 namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4927
4928 cur = tmp = elem = elem || document;
4929
4930 // Don't do events on text and comment nodes
4931 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4932 return;
4933 }
4934
4935 // focus/blur morphs to focusin/out; ensure we're not firing them right now
4936 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4937 return;
4938 }
4939
4940 if ( type.indexOf(".") >= 0 ) {
4941 // Namespaced trigger; create a regexp to match event type in handle()
4942 namespaces = type.split(".");
4943 type = namespaces.shift();
4944 namespaces.sort();
4945 }
4946 ontype = type.indexOf(":") < 0 && "on" + type;
4947
4948 // Caller can pass in a jQuery.Event object, Object, or just an event type string
4949 event = event[ jQuery.expando ] ?
4950 event :
4951 new jQuery.Event( type, typeof event === "object" && event );
4952
4953 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4954 event.isTrigger = onlyHandlers ? 2 : 3;
4955 event.namespace = namespaces.join(".");
4956 event.namespace_re = event.namespace ?
4957 new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4958 null;
4959
4960 // Clean up the event in case it is being reused
4961 event.result = undefined;
4962 if ( !event.target ) {
4963 event.target = elem;
4964 }
4965
4966 // Clone any incoming data and prepend the event, creating the handler arg list
4967 data = data == null ?
4968 [ event ] :
4969 jQuery.makeArray( data, [ event ] );
4970
4971 // Allow special events to draw outside the lines
4972 special = jQuery.event.special[ type ] || {};
4973 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4974 return;
4975 }
4976
4977 // Determine event propagation path in advance, per W3C events spec (#9951)
4978 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4979 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4980
4981 bubbleType = special.delegateType || type;
4982 if ( !rfocusMorph.test( bubbleType + type ) ) {
4983 cur = cur.parentNode;
4984 }
4985 for ( ; cur; cur = cur.parentNode ) {
4986 eventPath.push( cur );
4987 tmp = cur;
4988 }
4989
4990 // Only add window if we got to document (e.g., not plain obj or detached DOM)
4991 if ( tmp === (elem.ownerDocument || document) ) {
4992 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4993 }
4994 }
4995
4996 // Fire handlers on the event path
4997 i = 0;
4998 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4999
5000 event.type = i > 1 ?
5001 bubbleType :
5002 special.bindType || type;
5003
5004 // jQuery handler
5005 handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
5006 if ( handle ) {
5007 handle.apply( cur, data );
5008 }
5009
5010 // Native handler
5011 handle = ontype && cur[ ontype ];
5012 if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
5013 event.preventDefault();
5014 }
5015 }
5016 event.type = type;
5017
5018 // If nobody prevented the default action, do it now
5019 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
5020
5021 if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
5022 jQuery.acceptData( elem ) ) {
5023
5024 // Call a native DOM method on the target with the same name name as the event.
5025 // Can't use an .isFunction() check here because IE6/7 fails that test.
5026 // Don't do default actions on window, that's where global variables be (#6170)
5027 if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
5028
5029 // Don't re-trigger an onFOO event when we call its FOO() method
5030 tmp = elem[ ontype ];
5031
5032 if ( tmp ) {
5033 elem[ ontype ] = null;
5034 }
5035
5036 // Prevent re-triggering of the same event, since we already bubbled it above
5037 jQuery.event.triggered = type;
5038 try {
5039 elem[ type ]();
5040 } catch ( e ) {
5041 // IE<9 dies on focus/blur to hidden element (#1486,#12518)
5042 // only reproducible on winXP IE8 native, not IE9 in IE8 mode
5043 }
5044 jQuery.event.triggered = undefined;
5045
5046 if ( tmp ) {
5047 elem[ ontype ] = tmp;
5048 }
5049 }
5050 }
5051 }
5052
5053 return event.result;
5054 },
5055
5056 dispatch: function( event ) {
5057
5058 // Make a writable jQuery.Event from the native event object
5059 event = jQuery.event.fix( event );
5060
5061 var i, ret, handleObj, matched, j,
5062 handlerQueue = [],
5063 args = core_slice.call( arguments ),
5064 handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
5065 special = jQuery.event.special[ event.type ] || {};
5066
5067 // Use the fix-ed jQuery.Event rather than the (read-only) native event
5068 args[0] = event;
5069 event.delegateTarget = this;
5070
5071 // Call the preDispatch hook for the mapped type, and let it bail if desired
5072 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5073 return;
5074 }
5075
5076 // Determine handlers
5077 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5078
5079 // Run delegates first; they may want to stop propagation beneath us
5080 i = 0;
5081 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
5082 event.currentTarget = matched.elem;
5083
5084 j = 0;
5085 while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
5086
5087 // Triggered event must either 1) have no namespace, or
5088 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
5089 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
5090
5091 event.handleObj = handleObj;
5092 event.data = handleObj.data;
5093
5094 ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
5095 .apply( matched.elem, args );
5096
5097 if ( ret !== undefined ) {
5098 if ( (event.result = ret) === false ) {
5099 event.preventDefault();
5100 event.stopPropagation();
5101 }
5102 }
5103 }
5104 }
5105 }
5106
5107 // Call the postDispatch hook for the mapped type
5108 if ( special.postDispatch ) {
5109 special.postDispatch.call( this, event );
5110 }
5111
5112 return event.result;
5113 },
5114
5115 handlers: function( event, handlers ) {
5116 var sel, handleObj, matches, i,
5117 handlerQueue = [],
5118 delegateCount = handlers.delegateCount,
5119 cur = event.target;
5120
5121 // Find delegate handlers
5122 // Black-hole SVG <use> instance trees (#13180)
5123 // Avoid non-left-click bubbling in Firefox (#3861)
5124 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
5125
5126 /* jshint eqeqeq: false */
5127 for ( ; cur != this; cur = cur.parentNode || this ) {
5128 /* jshint eqeqeq: true */
5129
5130 // Don't check non-elements (#13208)
5131 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5132 if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
5133 matches = [];
5134 for ( i = 0; i < delegateCount; i++ ) {
5135 handleObj = handlers[ i ];
5136
5137 // Don't conflict with Object.prototype properties (#13203)
5138 sel = handleObj.selector + " ";
5139
5140 if ( matches[ sel ] === undefined ) {
5141 matches[ sel ] = handleObj.needsContext ?
5142 jQuery( sel, this ).index( cur ) >= 0 :
5143 jQuery.find( sel, this, null, [ cur ] ).length;
5144 }
5145 if ( matches[ sel ] ) {
5146 matches.push( handleObj );
5147 }
5148 }
5149 if ( matches.length ) {
5150 handlerQueue.push({ elem: cur, handlers: matches });
5151 }
5152 }
5153 }
5154 }
5155
5156 // Add the remaining (directly-bound) handlers
5157 if ( delegateCount < handlers.length ) {
5158 handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
5159 }
5160
5161 return handlerQueue;
5162 },
5163
5164 fix: function( event ) {
5165 if ( event[ jQuery.expando ] ) {
5166 return event;
5167 }
5168
5169 // Create a writable copy of the event object and normalize some properties
5170 var i, prop, copy,
5171 type = event.type,
5172 originalEvent = event,
5173 fixHook = this.fixHooks[ type ];
5174
5175 if ( !fixHook ) {
5176 this.fixHooks[ type ] = fixHook =
5177 rmouseEvent.test( type ) ? this.mouseHooks :
5178 rkeyEvent.test( type ) ? this.keyHooks :
5179 {};
5180 }
5181 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
5182
5183 event = new jQuery.Event( originalEvent );
5184
5185 i = copy.length;
5186 while ( i-- ) {
5187 prop = copy[ i ];
5188 event[ prop ] = originalEvent[ prop ];
5189 }
5190
5191 // Support: IE<9
5192 // Fix target property (#1925)
5193 if ( !event.target ) {
5194 event.target = originalEvent.srcElement || document;
5195 }
5196
5197 // Support: Chrome 23+, Safari?
5198 // Target should not be a text node (#504, #13143)
5199 if ( event.target.nodeType === 3 ) {
5200 event.target = event.target.parentNode;
5201 }
5202
5203 // Support: IE<9
5204 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
5205 event.metaKey = !!event.metaKey;
5206
5207 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
5208 },
5209
5210 // Includes some event props shared by KeyEvent and MouseEvent
5211 props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
5212
5213 fixHooks: {},
5214
5215 keyHooks: {
5216 props: "char charCode key keyCode".split(" "),
5217 filter: function( event, original ) {
5218
5219 // Add which for key events
5220 if ( event.which == null ) {
5221 event.which = original.charCode != null ? original.charCode : original.keyCode;
5222 }
5223
5224 return event;
5225 }
5226 },
5227
5228 mouseHooks: {
5229 props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
5230 filter: function( event, original ) {
5231 var body, eventDoc, doc,
5232 button = original.button,
5233 fromElement = original.fromElement;
5234
5235 // Calculate pageX/Y if missing and clientX/Y available
5236 if ( event.pageX == null && original.clientX != null ) {
5237 eventDoc = event.target.ownerDocument || document;
5238 doc = eventDoc.documentElement;
5239 body = eventDoc.body;
5240
5241 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
5242 event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
5243 }
5244
5245 // Add relatedTarget, if necessary
5246 if ( !event.relatedTarget && fromElement ) {
5247 event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
5248 }
5249
5250 // Add which for click: 1 === left; 2 === middle; 3 === right
5251 // Note: button is not normalized, so don't use it
5252 if ( !event.which && button !== undefined ) {
5253 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
5254 }
5255
5256 return event;
5257 }
5258 },
5259
5260 special: {
5261 load: {
5262 // Prevent triggered image.load events from bubbling to window.load
5263 noBubble: true
5264 },
5265 focus: {
5266 // Fire native event if possible so blur/focus sequence is correct
5267 trigger: function() {
5268 if ( this !== safeActiveElement() && this.focus ) {
5269 try {
5270 this.focus();
5271 return false;
5272 } catch ( e ) {
5273 // Support: IE<9
5274 // If we error on focus to hidden element (#1486, #12518),
5275 // let .trigger() run the handlers
5276 }
5277 }
5278 },
5279 delegateType: "focusin"
5280 },
5281 blur: {
5282 trigger: function() {
5283 if ( this === safeActiveElement() && this.blur ) {
5284 this.blur();
5285 return false;
5286 }
5287 },
5288 delegateType: "focusout"
5289 },
5290 click: {
5291 // For checkbox, fire native event so checked state will be right
5292 trigger: function() {
5293 if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
5294 this.click();
5295 return false;
5296 }
5297 },
5298
5299 // For cross-browser consistency, don't fire native .click() on links
5300 _default: function( event ) {
5301 return jQuery.nodeName( event.target, "a" );
5302 }
5303 },
5304
5305 beforeunload: {
5306 postDispatch: function( event ) {
5307
5308 // Even when returnValue equals to undefined Firefox will still show alert
5309 if ( event.result !== undefined ) {
5310 event.originalEvent.returnValue = event.result;
5311 }
5312 }
5313 }
5314 },
5315
5316 simulate: function( type, elem, event, bubble ) {
5317 // Piggyback on a donor event to simulate a different one.
5318 // Fake originalEvent to avoid donor's stopPropagation, but if the
5319 // simulated event prevents default then we do the same on the donor.
5320 var e = jQuery.extend(
5321 new jQuery.Event(),
5322 event,
5323 {
5324 type: type,
5325 isSimulated: true,
5326 originalEvent: {}
5327 }
5328 );
5329 if ( bubble ) {
5330 jQuery.event.trigger( e, null, elem );
5331 } else {
5332 jQuery.event.dispatch.call( elem, e );
5333 }
5334 if ( e.isDefaultPrevented() ) {
5335 event.preventDefault();
5336 }
5337 }
5338};
5339
5340jQuery.removeEvent = document.removeEventListener ?
5341 function( elem, type, handle ) {
5342 if ( elem.removeEventListener ) {
5343 elem.removeEventListener( type, handle, false );
5344 }
5345 } :
5346 function( elem, type, handle ) {
5347 var name = "on" + type;
5348
5349 if ( elem.detachEvent ) {
5350
5351 // #8545, #7054, preventing memory leaks for custom events in IE6-8
5352 // detachEvent needed property on element, by name of that event, to properly expose it to GC
5353 if ( typeof elem[ name ] === core_strundefined ) {
5354 elem[ name ] = null;
5355 }
5356
5357 elem.detachEvent( name, handle );
5358 }
5359 };
5360
5361jQuery.Event = function( src, props ) {
5362 // Allow instantiation without the 'new' keyword
5363 if ( !(this instanceof jQuery.Event) ) {
5364 return new jQuery.Event( src, props );
5365 }
5366
5367 // Event object
5368 if ( src && src.type ) {
5369 this.originalEvent = src;
5370 this.type = src.type;
5371
5372 // Events bubbling up the document may have been marked as prevented
5373 // by a handler lower down the tree; reflect the correct value.
5374 this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
5375 src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
5376
5377 // Event type
5378 } else {
5379 this.type = src;
5380 }
5381
5382 // Put explicitly provided properties onto the event object
5383 if ( props ) {
5384 jQuery.extend( this, props );
5385 }
5386
5387 // Create a timestamp if incoming event doesn't have one
5388 this.timeStamp = src && src.timeStamp || jQuery.now();
5389
5390 // Mark it as fixed
5391 this[ jQuery.expando ] = true;
5392};
5393
5394// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5395// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5396jQuery.Event.prototype = {
5397 isDefaultPrevented: returnFalse,
5398 isPropagationStopped: returnFalse,
5399 isImmediatePropagationStopped: returnFalse,
5400
5401 preventDefault: function() {
5402 var e = this.originalEvent;
5403
5404 this.isDefaultPrevented = returnTrue;
5405 if ( !e ) {
5406 return;
5407 }
5408
5409 // If preventDefault exists, run it on the original event
5410 if ( e.preventDefault ) {
5411 e.preventDefault();
5412
5413 // Support: IE
5414 // Otherwise set the returnValue property of the original event to false
5415 } else {
5416 e.returnValue = false;
5417 }
5418 },
5419 stopPropagation: function() {
5420 var e = this.originalEvent;
5421
5422 this.isPropagationStopped = returnTrue;
5423 if ( !e ) {
5424 return;
5425 }
5426 // If stopPropagation exists, run it on the original event
5427 if ( e.stopPropagation ) {
5428 e.stopPropagation();
5429 }
5430
5431 // Support: IE
5432 // Set the cancelBubble property of the original event to true
5433 e.cancelBubble = true;
5434 },
5435 stopImmediatePropagation: function() {
5436 this.isImmediatePropagationStopped = returnTrue;
5437 this.stopPropagation();
5438 }
5439};
5440
5441// Create mouseenter/leave events using mouseover/out and event-time checks
5442jQuery.each({
5443 mouseenter: "mouseover",
5444 mouseleave: "mouseout"
5445}, function( orig, fix ) {
5446 jQuery.event.special[ orig ] = {
5447 delegateType: fix,
5448 bindType: fix,
5449
5450 handle: function( event ) {
5451 var ret,
5452 target = this,
5453 related = event.relatedTarget,
5454 handleObj = event.handleObj;
5455
5456 // For mousenter/leave call the handler if related is outside the target.
5457 // NB: No relatedTarget if the mouse left/entered the browser window
5458 if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
5459 event.type = handleObj.origType;
5460 ret = handleObj.handler.apply( this, arguments );
5461 event.type = fix;
5462 }
5463 return ret;
5464 }
5465 };
5466});
5467
5468// IE submit delegation
5469if ( !jQuery.support.submitBubbles ) {
5470
5471 jQuery.event.special.submit = {
5472 setup: function() {
5473 // Only need this for delegated form submit events
5474 if ( jQuery.nodeName( this, "form" ) ) {
5475 return false;
5476 }
5477
5478 // Lazy-add a submit handler when a descendant form may potentially be submitted
5479 jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
5480 // Node name check avoids a VML-related crash in IE (#9807)
5481 var elem = e.target,
5482 form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
5483 if ( form && !jQuery._data( form, "submitBubbles" ) ) {
5484 jQuery.event.add( form, "submit._submit", function( event ) {
5485 event._submit_bubble = true;
5486 });
5487 jQuery._data( form, "submitBubbles", true );
5488 }
5489 });
5490 // return undefined since we don't need an event listener
5491 },
5492
5493 postDispatch: function( event ) {
5494 // If form was submitted by the user, bubble the event up the tree
5495 if ( event._submit_bubble ) {
5496 delete event._submit_bubble;
5497 if ( this.parentNode && !event.isTrigger ) {
5498 jQuery.event.simulate( "submit", this.parentNode, event, true );
5499 }
5500 }
5501 },
5502
5503 teardown: function() {
5504 // Only need this for delegated form submit events
5505 if ( jQuery.nodeName( this, "form" ) ) {
5506 return false;
5507 }
5508
5509 // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
5510 jQuery.event.remove( this, "._submit" );
5511 }
5512 };
5513}
5514
5515// IE change delegation and checkbox/radio fix
5516if ( !jQuery.support.changeBubbles ) {
5517
5518 jQuery.event.special.change = {
5519
5520 setup: function() {
5521
5522 if ( rformElems.test( this.nodeName ) ) {
5523 // IE doesn't fire change on a check/radio until blur; trigger it on click
5524 // after a propertychange. Eat the blur-change in special.change.handle.
5525 // This still fires onchange a second time for check/radio after blur.
5526 if ( this.type === "checkbox" || this.type === "radio" ) {
5527 jQuery.event.add( this, "propertychange._change", function( event ) {
5528 if ( event.originalEvent.propertyName === "checked" ) {
5529 this._just_changed = true;
5530 }
5531 });
5532 jQuery.event.add( this, "click._change", function( event ) {
5533 if ( this._just_changed && !event.isTrigger ) {
5534 this._just_changed = false;
5535 }
5536 // Allow triggered, simulated change events (#11500)
5537 jQuery.event.simulate( "change", this, event, true );
5538 });
5539 }
5540 return false;
5541 }
5542 // Delegated event; lazy-add a change handler on descendant inputs
5543 jQuery.event.add( this, "beforeactivate._change", function( e ) {
5544 var elem = e.target;
5545
5546 if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
5547 jQuery.event.add( elem, "change._change", function( event ) {
5548 if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
5549 jQuery.event.simulate( "change", this.parentNode, event, true );
5550 }
5551 });
5552 jQuery._data( elem, "changeBubbles", true );
5553 }
5554 });
5555 },
5556
5557 handle: function( event ) {
5558 var elem = event.target;
5559
5560 // Swallow native change events from checkbox/radio, we already triggered them above
5561 if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
5562 return event.handleObj.handler.apply( this, arguments );
5563 }
5564 },
5565
5566 teardown: function() {
5567 jQuery.event.remove( this, "._change" );
5568
5569 return !rformElems.test( this.nodeName );
5570 }
5571 };
5572}
5573
5574// Create "bubbling" focus and blur events
5575if ( !jQuery.support.focusinBubbles ) {
5576 jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
5577
5578 // Attach a single capturing handler while someone wants focusin/focusout
5579 var attaches = 0,
5580 handler = function( event ) {
5581 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
5582 };
5583
5584 jQuery.event.special[ fix ] = {
5585 setup: function() {
5586 if ( attaches++ === 0 ) {
5587 document.addEventListener( orig, handler, true );
5588 }
5589 },
5590 teardown: function() {
5591 if ( --attaches === 0 ) {
5592 document.removeEventListener( orig, handler, true );
5593 }
5594 }
5595 };
5596 });
5597}
5598
5599jQuery.fn.extend({
5600
5601 on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
5602 var type, origFn;
5603
5604 // Types can be a map of types/handlers
5605 if ( typeof types === "object" ) {
5606 // ( types-Object, selector, data )
5607 if ( typeof selector !== "string" ) {
5608 // ( types-Object, data )
5609 data = data || selector;
5610 selector = undefined;
5611 }
5612 for ( type in types ) {
5613 this.on( type, selector, data, types[ type ], one );
5614 }
5615 return this;
5616 }
5617
5618 if ( data == null && fn == null ) {
5619 // ( types, fn )
5620 fn = selector;
5621 data = selector = undefined;
5622 } else if ( fn == null ) {
5623 if ( typeof selector === "string" ) {
5624 // ( types, selector, fn )
5625 fn = data;
5626 data = undefined;
5627 } else {
5628 // ( types, data, fn )
5629 fn = data;
5630 data = selector;
5631 selector = undefined;
5632 }
5633 }
5634 if ( fn === false ) {
5635 fn = returnFalse;
5636 } else if ( !fn ) {
5637 return this;
5638 }
5639
5640 if ( one === 1 ) {
5641 origFn = fn;
5642 fn = function( event ) {
5643 // Can use an empty set, since event contains the info
5644 jQuery().off( event );
5645 return origFn.apply( this, arguments );
5646 };
5647 // Use same guid so caller can remove using origFn
5648 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
5649 }
5650 return this.each( function() {
5651 jQuery.event.add( this, types, fn, data, selector );
5652 });
5653 },
5654 one: function( types, selector, data, fn ) {
5655 return this.on( types, selector, data, fn, 1 );
5656 },
5657 off: function( types, selector, fn ) {
5658 var handleObj, type;
5659 if ( types && types.preventDefault && types.handleObj ) {
5660 // ( event ) dispatched jQuery.Event
5661 handleObj = types.handleObj;
5662 jQuery( types.delegateTarget ).off(
5663 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
5664 handleObj.selector,
5665 handleObj.handler
5666 );
5667 return this;
5668 }
5669 if ( typeof types === "object" ) {
5670 // ( types-object [, selector] )
5671 for ( type in types ) {
5672 this.off( type, selector, types[ type ] );
5673 }
5674 return this;
5675 }
5676 if ( selector === false || typeof selector === "function" ) {
5677 // ( types [, fn] )
5678 fn = selector;
5679 selector = undefined;
5680 }
5681 if ( fn === false ) {
5682 fn = returnFalse;
5683 }
5684 return this.each(function() {
5685 jQuery.event.remove( this, types, fn, selector );
5686 });
5687 },
5688
5689 trigger: function( type, data ) {
5690 return this.each(function() {
5691 jQuery.event.trigger( type, data, this );
5692 });
5693 },
5694 triggerHandler: function( type, data ) {
5695 var elem = this[0];
5696 if ( elem ) {
5697 return jQuery.event.trigger( type, data, elem, true );
5698 }
5699 }
5700});
5701var isSimple = /^.[^:#\[\.,]*$/,
5702 rparentsprev = /^(?:parents|prev(?:Until|All))/,
5703 rneedsContext = jQuery.expr.match.needsContext,
5704 // methods guaranteed to produce a unique set when starting from a unique set
5705 guaranteedUnique = {
5706 children: true,
5707 contents: true,
5708 next: true,
5709 prev: true
5710 };
5711
5712jQuery.fn.extend({
5713 find: function( selector ) {
5714 var i,
5715 ret = [],
5716 self = this,
5717 len = self.length;
5718
5719 if ( typeof selector !== "string" ) {
5720 return this.pushStack( jQuery( selector ).filter(function() {
5721 for ( i = 0; i < len; i++ ) {
5722 if ( jQuery.contains( self[ i ], this ) ) {
5723 return true;
5724 }
5725 }
5726 }) );
5727 }
5728
5729 for ( i = 0; i < len; i++ ) {
5730 jQuery.find( selector, self[ i ], ret );
5731 }
5732
5733 // Needed because $( selector, context ) becomes $( context ).find( selector )
5734 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5735 ret.selector = this.selector ? this.selector + " " + selector : selector;
5736 return ret;
5737 },
5738
5739 has: function( target ) {
5740 var i,
5741 targets = jQuery( target, this ),
5742 len = targets.length;
5743
5744 return this.filter(function() {
5745 for ( i = 0; i < len; i++ ) {
5746 if ( jQuery.contains( this, targets[i] ) ) {
5747 return true;
5748 }
5749 }
5750 });
5751 },
5752
5753 not: function( selector ) {
5754 return this.pushStack( winnow(this, selector || [], true) );
5755 },
5756
5757 filter: function( selector ) {
5758 return this.pushStack( winnow(this, selector || [], false) );
5759 },
5760
5761 is: function( selector ) {
5762 return !!winnow(
5763 this,
5764
5765 // If this is a positional/relative selector, check membership in the returned set
5766 // so $("p:first").is("p:last") won't return true for a doc with two "p".
5767 typeof selector === "string" && rneedsContext.test( selector ) ?
5768 jQuery( selector ) :
5769 selector || [],
5770 false
5771 ).length;
5772 },
5773
5774 closest: function( selectors, context ) {
5775 var cur,
5776 i = 0,
5777 l = this.length,
5778 ret = [],
5779 pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
5780 jQuery( selectors, context || this.context ) :
5781 0;
5782
5783 for ( ; i < l; i++ ) {
5784 for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
5785 // Always skip document fragments
5786 if ( cur.nodeType < 11 && (pos ?
5787 pos.index(cur) > -1 :
5788
5789 // Don't pass non-elements to Sizzle
5790 cur.nodeType === 1 &&
5791 jQuery.find.matchesSelector(cur, selectors)) ) {
5792
5793 cur = ret.push( cur );
5794 break;
5795 }
5796 }
5797 }
5798
5799 return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
5800 },
5801
5802 // Determine the position of an element within
5803 // the matched set of elements
5804 index: function( elem ) {
5805
5806 // No argument, return index in parent
5807 if ( !elem ) {
5808 return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
5809 }
5810
5811 // index in selector
5812 if ( typeof elem === "string" ) {
5813 return jQuery.inArray( this[0], jQuery( elem ) );
5814 }
5815
5816 // Locate the position of the desired element
5817 return jQuery.inArray(
5818 // If it receives a jQuery object, the first element is used
5819 elem.jquery ? elem[0] : elem, this );
5820 },
5821
5822 add: function( selector, context ) {
5823 var set = typeof selector === "string" ?
5824 jQuery( selector, context ) :
5825 jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5826 all = jQuery.merge( this.get(), set );
5827
5828 return this.pushStack( jQuery.unique(all) );
5829 },
5830
5831 addBack: function( selector ) {
5832 return this.add( selector == null ?
5833 this.prevObject : this.prevObject.filter(selector)
5834 );
5835 }
5836});
5837
5838function sibling( cur, dir ) {
5839 do {
5840 cur = cur[ dir ];
5841 } while ( cur && cur.nodeType !== 1 );
5842
5843 return cur;
5844}
5845
5846jQuery.each({
5847 parent: function( elem ) {
5848 var parent = elem.parentNode;
5849 return parent && parent.nodeType !== 11 ? parent : null;
5850 },
5851 parents: function( elem ) {
5852 return jQuery.dir( elem, "parentNode" );
5853 },
5854 parentsUntil: function( elem, i, until ) {
5855 return jQuery.dir( elem, "parentNode", until );
5856 },
5857 next: function( elem ) {
5858 return sibling( elem, "nextSibling" );
5859 },
5860 prev: function( elem ) {
5861 return sibling( elem, "previousSibling" );
5862 },
5863 nextAll: function( elem ) {
5864 return jQuery.dir( elem, "nextSibling" );
5865 },
5866 prevAll: function( elem ) {
5867 return jQuery.dir( elem, "previousSibling" );
5868 },
5869 nextUntil: function( elem, i, until ) {
5870 return jQuery.dir( elem, "nextSibling", until );
5871 },
5872 prevUntil: function( elem, i, until ) {
5873 return jQuery.dir( elem, "previousSibling", until );
5874 },
5875 siblings: function( elem ) {
5876 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5877 },
5878 children: function( elem ) {
5879 return jQuery.sibling( elem.firstChild );
5880 },
5881 contents: function( elem ) {
5882 return jQuery.nodeName( elem, "iframe" ) ?
5883 elem.contentDocument || elem.contentWindow.document :
5884 jQuery.merge( [], elem.childNodes );
5885 }
5886}, function( name, fn ) {
5887 jQuery.fn[ name ] = function( until, selector ) {
5888 var ret = jQuery.map( this, fn, until );
5889
5890 if ( name.slice( -5 ) !== "Until" ) {
5891 selector = until;
5892 }
5893
5894 if ( selector && typeof selector === "string" ) {
5895 ret = jQuery.filter( selector, ret );
5896 }
5897
5898 if ( this.length > 1 ) {
5899 // Remove duplicates
5900 if ( !guaranteedUnique[ name ] ) {
5901 ret = jQuery.unique( ret );
5902 }
5903
5904 // Reverse order for parents* and prev-derivatives
5905 if ( rparentsprev.test( name ) ) {
5906 ret = ret.reverse();
5907 }
5908 }
5909
5910 return this.pushStack( ret );
5911 };
5912});
5913
5914jQuery.extend({
5915 filter: function( expr, elems, not ) {
5916 var elem = elems[ 0 ];
5917
5918 if ( not ) {
5919 expr = ":not(" + expr + ")";
5920 }
5921
5922 return elems.length === 1 && elem.nodeType === 1 ?
5923 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
5924 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
5925 return elem.nodeType === 1;
5926 }));
5927 },
5928
5929 dir: function( elem, dir, until ) {
5930 var matched = [],
5931 cur = elem[ dir ];
5932
5933 while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
5934 if ( cur.nodeType === 1 ) {
5935 matched.push( cur );
5936 }
5937 cur = cur[dir];
5938 }
5939 return matched;
5940 },
5941
5942 sibling: function( n, elem ) {
5943 var r = [];
5944
5945 for ( ; n; n = n.nextSibling ) {
5946 if ( n.nodeType === 1 && n !== elem ) {
5947 r.push( n );
5948 }
5949 }
5950
5951 return r;
5952 }
5953});
5954
5955// Implement the identical functionality for filter and not
5956function winnow( elements, qualifier, not ) {
5957 if ( jQuery.isFunction( qualifier ) ) {
5958 return jQuery.grep( elements, function( elem, i ) {
5959 /* jshint -W018 */
5960 return !!qualifier.call( elem, i, elem ) !== not;
5961 });
5962
5963 }
5964
5965 if ( qualifier.nodeType ) {
5966 return jQuery.grep( elements, function( elem ) {
5967 return ( elem === qualifier ) !== not;
5968 });
5969
5970 }
5971
5972 if ( typeof qualifier === "string" ) {
5973 if ( isSimple.test( qualifier ) ) {
5974 return jQuery.filter( qualifier, elements, not );
5975 }
5976
5977 qualifier = jQuery.filter( qualifier, elements );
5978 }
5979
5980 return jQuery.grep( elements, function( elem ) {
5981 return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
5982 });
5983}
5984function createSafeFragment( document ) {
5985 var list = nodeNames.split( "|" ),
5986 safeFrag = document.createDocumentFragment();
5987
5988 if ( safeFrag.createElement ) {
5989 while ( list.length ) {
5990 safeFrag.createElement(
5991 list.pop()
5992 );
5993 }
5994 }
5995 return safeFrag;
5996}
5997
5998var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5999 "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
6000 rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
6001 rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
6002 rleadingWhitespace = /^\s+/,
6003 rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
6004 rtagName = /<([\w:]+)/,
6005 rtbody = /<tbody/i,
6006 rhtml = /<|&#?\w+;/,
6007 rnoInnerhtml = /<(?:script|style|link)/i,
6008 manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
6009 // checked="checked" or checked
6010 rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
6011 rscriptType = /^$|\/(?:java|ecma)script/i,
6012 rscriptTypeMasked = /^true\/(.*)/,
6013 rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
6014
6015 // We have to close these tags to support XHTML (#13200)
6016 wrapMap = {
6017 option: [ 1, "<select multiple='multiple'>", "</select>" ],
6018 legend: [ 1, "<fieldset>", "</fieldset>" ],
6019 area: [ 1, "<map>", "</map>" ],
6020 param: [ 1, "<object>", "</object>" ],
6021 thead: [ 1, "<table>", "</table>" ],
6022 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
6023 col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
6024 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
6025
6026 // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
6027 // unless wrapped in a div with non-breaking characters in front of it.
6028 _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
6029 },
6030 safeFragment = createSafeFragment( document ),
6031 fragmentDiv = safeFragment.appendChild( document.createElement("div") );
6032
6033wrapMap.optgroup = wrapMap.option;
6034wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
6035wrapMap.th = wrapMap.td;
6036
6037jQuery.fn.extend({
6038 text: function( value ) {
6039 return jQuery.access( this, function( value ) {
6040 return value === undefined ?
6041 jQuery.text( this ) :
6042 this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
6043 }, null, value, arguments.length );
6044 },
6045
6046 append: function() {
6047 return this.domManip( arguments, function( elem ) {
6048 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6049 var target = manipulationTarget( this, elem );
6050 target.appendChild( elem );
6051 }
6052 });
6053 },
6054
6055 prepend: function() {
6056 return this.domManip( arguments, function( elem ) {
6057 if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
6058 var target = manipulationTarget( this, elem );
6059 target.insertBefore( elem, target.firstChild );
6060 }
6061 });
6062 },
6063
6064 before: function() {
6065 return this.domManip( arguments, function( elem ) {
6066 if ( this.parentNode ) {
6067 this.parentNode.insertBefore( elem, this );
6068 }
6069 });
6070 },
6071
6072 after: function() {
6073 return this.domManip( arguments, function( elem ) {
6074 if ( this.parentNode ) {
6075 this.parentNode.insertBefore( elem, this.nextSibling );
6076 }
6077 });
6078 },
6079
6080 // keepData is for internal use only--do not document
6081 remove: function( selector, keepData ) {
6082 var elem,
6083 elems = selector ? jQuery.filter( selector, this ) : this,
6084 i = 0;
6085
6086 for ( ; (elem = elems[i]) != null; i++ ) {
6087
6088 if ( !keepData && elem.nodeType === 1 ) {
6089 jQuery.cleanData( getAll( elem ) );
6090 }
6091
6092 if ( elem.parentNode ) {
6093 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
6094 setGlobalEval( getAll( elem, "script" ) );
6095 }
6096 elem.parentNode.removeChild( elem );
6097 }
6098 }
6099
6100 return this;
6101 },
6102
6103 empty: function() {
6104 var elem,
6105 i = 0;
6106
6107 for ( ; (elem = this[i]) != null; i++ ) {
6108 // Remove element nodes and prevent memory leaks
6109 if ( elem.nodeType === 1 ) {
6110 jQuery.cleanData( getAll( elem, false ) );
6111 }
6112
6113 // Remove any remaining nodes
6114 while ( elem.firstChild ) {
6115 elem.removeChild( elem.firstChild );
6116 }
6117
6118 // If this is a select, ensure that it displays empty (#12336)
6119 // Support: IE<9
6120 if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6121 elem.options.length = 0;
6122 }
6123 }
6124
6125 return this;
6126 },
6127
6128 clone: function( dataAndEvents, deepDataAndEvents ) {
6129 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6130 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6131
6132 return this.map( function () {
6133 return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6134 });
6135 },
6136
6137 html: function( value ) {
6138 return jQuery.access( this, function( value ) {
6139 var elem = this[0] || {},
6140 i = 0,
6141 l = this.length;
6142
6143 if ( value === undefined ) {
6144 return elem.nodeType === 1 ?
6145 elem.innerHTML.replace( rinlinejQuery, "" ) :
6146 undefined;
6147 }
6148
6149 // See if we can take a shortcut and just use innerHTML
6150 if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6151 ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
6152 ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6153 !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
6154
6155 value = value.replace( rxhtmlTag, "<$1></$2>" );
6156
6157 try {
6158 for (; i < l; i++ ) {
6159 // Remove element nodes and prevent memory leaks
6160 elem = this[i] || {};
6161 if ( elem.nodeType === 1 ) {
6162 jQuery.cleanData( getAll( elem, false ) );
6163 elem.innerHTML = value;
6164 }
6165 }
6166
6167 elem = 0;
6168
6169 // If using innerHTML throws an exception, use the fallback method
6170 } catch(e) {}
6171 }
6172
6173 if ( elem ) {
6174 this.empty().append( value );
6175 }
6176 }, null, value, arguments.length );
6177 },
6178
6179 replaceWith: function() {
6180 var
6181 // Snapshot the DOM in case .domManip sweeps something relevant into its fragment
6182 args = jQuery.map( this, function( elem ) {
6183 return [ elem.nextSibling, elem.parentNode ];
6184 }),
6185 i = 0;
6186
6187 // Make the changes, replacing each context element with the new content
6188 this.domManip( arguments, function( elem ) {
6189 var next = args[ i++ ],
6190 parent = args[ i++ ];
6191
6192 if ( parent ) {
6193 // Don't use the snapshot next if it has moved (#13810)
6194 if ( next && next.parentNode !== parent ) {
6195 next = this.nextSibling;
6196 }
6197 jQuery( this ).remove();
6198 parent.insertBefore( elem, next );
6199 }
6200 // Allow new content to include elements from the context set
6201 }, true );
6202
6203 // Force removal if there was no new content (e.g., from empty arguments)
6204 return i ? this : this.remove();
6205 },
6206
6207 detach: function( selector ) {
6208 return this.remove( selector, true );
6209 },
6210
6211 domManip: function( args, callback, allowIntersection ) {
6212
6213 // Flatten any nested arrays
6214 args = core_concat.apply( [], args );
6215
6216 var first, node, hasScripts,
6217 scripts, doc, fragment,
6218 i = 0,
6219 l = this.length,
6220 set = this,
6221 iNoClone = l - 1,
6222 value = args[0],
6223 isFunction = jQuery.isFunction( value );
6224
6225 // We can't cloneNode fragments that contain checked, in WebKit
6226 if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
6227 return this.each(function( index ) {
6228 var self = set.eq( index );
6229 if ( isFunction ) {
6230 args[0] = value.call( this, index, self.html() );
6231 }
6232 self.domManip( args, callback, allowIntersection );
6233 });
6234 }
6235
6236 if ( l ) {
6237 fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, !allowIntersection && this );
6238 first = fragment.firstChild;
6239
6240 if ( fragment.childNodes.length === 1 ) {
6241 fragment = first;
6242 }
6243
6244 if ( first ) {
6245 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6246 hasScripts = scripts.length;
6247
6248 // Use the original fragment for the last item instead of the first because it can end up
6249 // being emptied incorrectly in certain situations (#8070).
6250 for ( ; i < l; i++ ) {
6251 node = fragment;
6252
6253 if ( i !== iNoClone ) {
6254 node = jQuery.clone( node, true, true );
6255
6256 // Keep references to cloned scripts for later restoration
6257 if ( hasScripts ) {
6258 jQuery.merge( scripts, getAll( node, "script" ) );
6259 }
6260 }
6261
6262 callback.call( this[i], node, i );
6263 }
6264
6265 if ( hasScripts ) {
6266 doc = scripts[ scripts.length - 1 ].ownerDocument;
6267
6268 // Reenable scripts
6269 jQuery.map( scripts, restoreScript );
6270
6271 // Evaluate executable scripts on first document insertion
6272 for ( i = 0; i < hasScripts; i++ ) {
6273 node = scripts[ i ];
6274 if ( rscriptType.test( node.type || "" ) &&
6275 !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6276
6277 if ( node.src ) {
6278 // Hope ajax is available...
6279 jQuery._evalUrl( node.src );
6280 } else {
6281 jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6282 }
6283 }
6284 }
6285 }
6286
6287 // Fix #11809: Avoid leaking memory
6288 fragment = first = null;
6289 }
6290 }
6291
6292 return this;
6293 }
6294});
6295
6296// Support: IE<8
6297// Manipulating tables requires a tbody
6298function manipulationTarget( elem, content ) {
6299 return jQuery.nodeName( elem, "table" ) &&
6300 jQuery.nodeName( content.nodeType === 1 ? content : content.firstChild, "tr" ) ?
6301
6302 elem.getElementsByTagName("tbody")[0] ||
6303 elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
6304 elem;
6305}
6306
6307// Replace/restore the type attribute of script elements for safe DOM manipulation
6308function disableScript( elem ) {
6309 elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
6310 return elem;
6311}
6312function restoreScript( elem ) {
6313 var match = rscriptTypeMasked.exec( elem.type );
6314 if ( match ) {
6315 elem.type = match[1];
6316 } else {
6317 elem.removeAttribute("type");
6318 }
6319 return elem;
6320}
6321
6322// Mark scripts as having already been evaluated
6323function setGlobalEval( elems, refElements ) {
6324 var elem,
6325 i = 0;
6326 for ( ; (elem = elems[i]) != null; i++ ) {
6327 jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
6328 }
6329}
6330
6331function cloneCopyEvent( src, dest ) {
6332
6333 if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6334 return;
6335 }
6336
6337 var type, i, l,
6338 oldData = jQuery._data( src ),
6339 curData = jQuery._data( dest, oldData ),
6340 events = oldData.events;
6341
6342 if ( events ) {
6343 delete curData.handle;
6344 curData.events = {};
6345
6346 for ( type in events ) {
6347 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6348 jQuery.event.add( dest, type, events[ type ][ i ] );
6349 }
6350 }
6351 }
6352
6353 // make the cloned public data object a copy from the original
6354 if ( curData.data ) {
6355 curData.data = jQuery.extend( {}, curData.data );
6356 }
6357}
6358
6359function fixCloneNodeIssues( src, dest ) {
6360 var nodeName, e, data;
6361
6362 // We do not need to do anything for non-Elements
6363 if ( dest.nodeType !== 1 ) {
6364 return;
6365 }
6366
6367 nodeName = dest.nodeName.toLowerCase();
6368
6369 // IE6-8 copies events bound via attachEvent when using cloneNode.
6370 if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
6371 data = jQuery._data( dest );
6372
6373 for ( e in data.events ) {
6374 jQuery.removeEvent( dest, e, data.handle );
6375 }
6376
6377 // Event data gets referenced instead of copied if the expando gets copied too
6378 dest.removeAttribute( jQuery.expando );
6379 }
6380
6381 // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
6382 if ( nodeName === "script" && dest.text !== src.text ) {
6383 disableScript( dest ).text = src.text;
6384 restoreScript( dest );
6385
6386 // IE6-10 improperly clones children of object elements using classid.
6387 // IE10 throws NoModificationAllowedError if parent is null, #12132.
6388 } else if ( nodeName === "object" ) {
6389 if ( dest.parentNode ) {
6390 dest.outerHTML = src.outerHTML;
6391 }
6392
6393 // This path appears unavoidable for IE9. When cloning an object
6394 // element in IE9, the outerHTML strategy above is not sufficient.
6395 // If the src has innerHTML and the destination does not,
6396 // copy the src.innerHTML into the dest.innerHTML. #10324
6397 if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
6398 dest.innerHTML = src.innerHTML;
6399 }
6400
6401 } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
6402 // IE6-8 fails to persist the checked state of a cloned checkbox
6403 // or radio button. Worse, IE6-7 fail to give the cloned element
6404 // a checked appearance if the defaultChecked value isn't also set
6405
6406 dest.defaultChecked = dest.checked = src.checked;
6407
6408 // IE6-7 get confused and end up setting the value of a cloned
6409 // checkbox/radio button to an empty string instead of "on"
6410 if ( dest.value !== src.value ) {
6411 dest.value = src.value;
6412 }
6413
6414 // IE6-8 fails to return the selected option to the default selected
6415 // state when cloning options
6416 } else if ( nodeName === "option" ) {
6417 dest.defaultSelected = dest.selected = src.defaultSelected;
6418
6419 // IE6-8 fails to set the defaultValue to the correct value when
6420 // cloning other types of input fields
6421 } else if ( nodeName === "input" || nodeName === "textarea" ) {
6422 dest.defaultValue = src.defaultValue;
6423 }
6424}
6425
6426jQuery.each({
6427 appendTo: "append",
6428 prependTo: "prepend",
6429 insertBefore: "before",
6430 insertAfter: "after",
6431 replaceAll: "replaceWith"
6432}, function( name, original ) {
6433 jQuery.fn[ name ] = function( selector ) {
6434 var elems,
6435 i = 0,
6436 ret = [],
6437 insert = jQuery( selector ),
6438 last = insert.length - 1;
6439
6440 for ( ; i <= last; i++ ) {
6441 elems = i === last ? this : this.clone(true);
6442 jQuery( insert[i] )[ original ]( elems );
6443
6444 // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6445 core_push.apply( ret, elems.get() );
6446 }
6447
6448 return this.pushStack( ret );
6449 };
6450});
6451
6452function getAll( context, tag ) {
6453 var elems, elem,
6454 i = 0,
6455 found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
6456 typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
6457 undefined;
6458
6459 if ( !found ) {
6460 for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
6461 if ( !tag || jQuery.nodeName( elem, tag ) ) {
6462 found.push( elem );
6463 } else {
6464 jQuery.merge( found, getAll( elem, tag ) );
6465 }
6466 }
6467 }
6468
6469 return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
6470 jQuery.merge( [ context ], found ) :
6471 found;
6472}
6473
6474// Used in buildFragment, fixes the defaultChecked property
6475function fixDefaultChecked( elem ) {
6476 if ( manipulation_rcheckableType.test( elem.type ) ) {
6477 elem.defaultChecked = elem.checked;
6478 }
6479}
6480
6481jQuery.extend({
6482 clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6483 var destElements, node, clone, i, srcElements,
6484 inPage = jQuery.contains( elem.ownerDocument, elem );
6485
6486 if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
6487 clone = elem.cloneNode( true );
6488
6489 // IE<=8 does not properly clone detached, unknown element nodes
6490 } else {
6491 fragmentDiv.innerHTML = elem.outerHTML;
6492 fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
6493 }
6494
6495 if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6496 (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6497
6498 // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
6499 destElements = getAll( clone );
6500 srcElements = getAll( elem );
6501
6502 // Fix all IE cloning issues
6503 for ( i = 0; (node = srcElements[i]) != null; ++i ) {
6504 // Ensure that the destination node is not null; Fixes #9587
6505 if ( destElements[i] ) {
6506 fixCloneNodeIssues( node, destElements[i] );
6507 }
6508 }
6509 }
6510
6511 // Copy the events from the original to the clone
6512 if ( dataAndEvents ) {
6513 if ( deepDataAndEvents ) {
6514 srcElements = srcElements || getAll( elem );
6515 destElements = destElements || getAll( clone );
6516
6517 for ( i = 0; (node = srcElements[i]) != null; i++ ) {
6518 cloneCopyEvent( node, destElements[i] );
6519 }
6520 } else {
6521 cloneCopyEvent( elem, clone );
6522 }
6523 }
6524
6525 // Preserve script evaluation history
6526 destElements = getAll( clone, "script" );
6527 if ( destElements.length > 0 ) {
6528 setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6529 }
6530
6531 destElements = srcElements = node = null;
6532
6533 // Return the cloned set
6534 return clone;
6535 },
6536
6537 buildFragment: function( elems, context, scripts, selection ) {
6538 var j, elem, contains,
6539 tmp, tag, tbody, wrap,
6540 l = elems.length,
6541
6542 // Ensure a safe fragment
6543 safe = createSafeFragment( context ),
6544
6545 nodes = [],
6546 i = 0;
6547
6548 for ( ; i < l; i++ ) {
6549 elem = elems[ i ];
6550
6551 if ( elem || elem === 0 ) {
6552
6553 // Add nodes directly
6554 if ( jQuery.type( elem ) === "object" ) {
6555 jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
6556
6557 // Convert non-html into a text node
6558 } else if ( !rhtml.test( elem ) ) {
6559 nodes.push( context.createTextNode( elem ) );
6560
6561 // Convert html into DOM nodes
6562 } else {
6563 tmp = tmp || safe.appendChild( context.createElement("div") );
6564
6565 // Deserialize a standard representation
6566 tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
6567 wrap = wrapMap[ tag ] || wrapMap._default;
6568
6569 tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
6570
6571 // Descend through wrappers to the right content
6572 j = wrap[0];
6573 while ( j-- ) {
6574 tmp = tmp.lastChild;
6575 }
6576
6577 // Manually add leading whitespace removed by IE
6578 if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6579 nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
6580 }
6581
6582 // Remove IE's autoinserted <tbody> from table fragments
6583 if ( !jQuery.support.tbody ) {
6584
6585 // String was a <table>, *may* have spurious <tbody>
6586 elem = tag === "table" && !rtbody.test( elem ) ?
6587 tmp.firstChild :
6588
6589 // String was a bare <thead> or <tfoot>
6590 wrap[1] === "<table>" && !rtbody.test( elem ) ?
6591 tmp :
6592 0;
6593
6594 j = elem && elem.childNodes.length;
6595 while ( j-- ) {
6596 if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
6597 elem.removeChild( tbody );
6598 }
6599 }
6600 }
6601
6602 jQuery.merge( nodes, tmp.childNodes );
6603
6604 // Fix #12392 for WebKit and IE > 9
6605 tmp.textContent = "";
6606
6607 // Fix #12392 for oldIE
6608 while ( tmp.firstChild ) {
6609 tmp.removeChild( tmp.firstChild );
6610 }
6611
6612 // Remember the top-level container for proper cleanup
6613 tmp = safe.lastChild;
6614 }
6615 }
6616 }
6617
6618 // Fix #11356: Clear elements from fragment
6619 if ( tmp ) {
6620 safe.removeChild( tmp );
6621 }
6622
6623 // Reset defaultChecked for any radios and checkboxes
6624 // about to be appended to the DOM in IE 6/7 (#8060)
6625 if ( !jQuery.support.appendChecked ) {
6626 jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6627 }
6628
6629 i = 0;
6630 while ( (elem = nodes[ i++ ]) ) {
6631
6632 // #4087 - If origin and destination elements are the same, and this is
6633 // that element, do not do anything
6634 if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6635 continue;
6636 }
6637
6638 contains = jQuery.contains( elem.ownerDocument, elem );
6639
6640 // Append to fragment
6641 tmp = getAll( safe.appendChild( elem ), "script" );
6642
6643 // Preserve script evaluation history
6644 if ( contains ) {
6645 setGlobalEval( tmp );
6646 }
6647
6648 // Capture executables
6649 if ( scripts ) {
6650 j = 0;
6651 while ( (elem = tmp[ j++ ]) ) {
6652 if ( rscriptType.test( elem.type || "" ) ) {
6653 scripts.push( elem );
6654 }
6655 }
6656 }
6657 }
6658
6659 tmp = null;
6660
6661 return safe;
6662 },
6663
6664 cleanData: function( elems, /* internal */ acceptData ) {
6665 var elem, type, id, data,
6666 i = 0,
6667 internalKey = jQuery.expando,
6668 cache = jQuery.cache,
6669 deleteExpando = jQuery.support.deleteExpando,
6670 special = jQuery.event.special;
6671
6672 for ( ; (elem = elems[i]) != null; i++ ) {
6673
6674 if ( acceptData || jQuery.acceptData( elem ) ) {
6675
6676 id = elem[ internalKey ];
6677 data = id && cache[ id ];
6678
6679 if ( data ) {
6680 if ( data.events ) {
6681 for ( type in data.events ) {
6682 if ( special[ type ] ) {
6683 jQuery.event.remove( elem, type );
6684
6685 // This is a shortcut to avoid jQuery.event.remove's overhead
6686 } else {
6687 jQuery.removeEvent( elem, type, data.handle );
6688 }
6689 }
6690 }
6691
6692 // Remove cache only if it was not already removed by jQuery.event.remove
6693 if ( cache[ id ] ) {
6694
6695 delete cache[ id ];
6696
6697 // IE does not allow us to delete expando properties from nodes,
6698 // nor does it have a removeAttribute function on Document nodes;
6699 // we must handle all of these cases
6700 if ( deleteExpando ) {
6701 delete elem[ internalKey ];
6702
6703 } else if ( typeof elem.removeAttribute !== core_strundefined ) {
6704 elem.removeAttribute( internalKey );
6705
6706 } else {
6707 elem[ internalKey ] = null;
6708 }
6709
6710 core_deletedIds.push( id );
6711 }
6712 }
6713 }
6714 }
6715 },
6716
6717 _evalUrl: function( url ) {
6718 return jQuery.ajax({
6719 url: url,
6720 type: "GET",
6721 dataType: "script",
6722 async: false,
6723 global: false,
6724 "throws": true
6725 });
6726 }
6727});
6728jQuery.fn.extend({
6729 wrapAll: function( html ) {
6730 if ( jQuery.isFunction( html ) ) {
6731 return this.each(function(i) {
6732 jQuery(this).wrapAll( html.call(this, i) );
6733 });
6734 }
6735
6736 if ( this[0] ) {
6737 // The elements to wrap the target around
6738 var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
6739
6740 if ( this[0].parentNode ) {
6741 wrap.insertBefore( this[0] );
6742 }
6743
6744 wrap.map(function() {
6745 var elem = this;
6746
6747 while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
6748 elem = elem.firstChild;
6749 }
6750
6751 return elem;
6752 }).append( this );
6753 }
6754
6755 return this;
6756 },
6757
6758 wrapInner: function( html ) {
6759 if ( jQuery.isFunction( html ) ) {
6760 return this.each(function(i) {
6761 jQuery(this).wrapInner( html.call(this, i) );
6762 });
6763 }
6764
6765 return this.each(function() {
6766 var self = jQuery( this ),
6767 contents = self.contents();
6768
6769 if ( contents.length ) {
6770 contents.wrapAll( html );
6771
6772 } else {
6773 self.append( html );
6774 }
6775 });
6776 },
6777
6778 wrap: function( html ) {
6779 var isFunction = jQuery.isFunction( html );
6780
6781 return this.each(function(i) {
6782 jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
6783 });
6784 },
6785
6786 unwrap: function() {
6787 return this.parent().each(function() {
6788 if ( !jQuery.nodeName( this, "body" ) ) {
6789 jQuery( this ).replaceWith( this.childNodes );
6790 }
6791 }).end();
6792 }
6793});
6794var iframe, getStyles, curCSS,
6795 ralpha = /alpha\([^)]*\)/i,
6796 ropacity = /opacity\s*=\s*([^)]*)/,
6797 rposition = /^(top|right|bottom|left)$/,
6798 // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6799 // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6800 rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6801 rmargin = /^margin/,
6802 rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6803 rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6804 rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6805 elemdisplay = { BODY: "block" },
6806
6807 cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6808 cssNormalTransform = {
6809 letterSpacing: 0,
6810 fontWeight: 400
6811 },
6812
6813 cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6814 cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6815
6816// return a css property mapped to a potentially vendor prefixed property
6817function vendorPropName( style, name ) {
6818
6819 // shortcut for names that are not vendor prefixed
6820 if ( name in style ) {
6821 return name;
6822 }
6823
6824 // check for vendor prefixed names
6825 var capName = name.charAt(0).toUpperCase() + name.slice(1),
6826 origName = name,
6827 i = cssPrefixes.length;
6828
6829 while ( i-- ) {
6830 name = cssPrefixes[ i ] + capName;
6831 if ( name in style ) {
6832 return name;
6833 }
6834 }
6835
6836 return origName;
6837}
6838
6839function isHidden( elem, el ) {
6840 // isHidden might be called from jQuery#filter function;
6841 // in that case, element will be second argument
6842 elem = el || elem;
6843 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6844}
6845
6846function showHide( elements, show ) {
6847 var display, elem, hidden,
6848 values = [],
6849 index = 0,
6850 length = elements.length;
6851
6852 for ( ; index < length; index++ ) {
6853 elem = elements[ index ];
6854 if ( !elem.style ) {
6855 continue;
6856 }
6857
6858 values[ index ] = jQuery._data( elem, "olddisplay" );
6859 display = elem.style.display;
6860 if ( show ) {
6861 // Reset the inline display of this element to learn if it is
6862 // being hidden by cascaded rules or not
6863 if ( !values[ index ] && display === "none" ) {
6864 elem.style.display = "";
6865 }
6866
6867 // Set elements which have been overridden with display: none
6868 // in a stylesheet to whatever the default browser style is
6869 // for such an element
6870 if ( elem.style.display === "" && isHidden( elem ) ) {
6871 values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6872 }
6873 } else {
6874
6875 if ( !values[ index ] ) {
6876 hidden = isHidden( elem );
6877
6878 if ( display && display !== "none" || !hidden ) {
6879 jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6880 }
6881 }
6882 }
6883 }
6884
6885 // Set the display of most of the elements in a second loop
6886 // to avoid the constant reflow
6887 for ( index = 0; index < length; index++ ) {
6888 elem = elements[ index ];
6889 if ( !elem.style ) {
6890 continue;
6891 }
6892 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6893 elem.style.display = show ? values[ index ] || "" : "none";
6894 }
6895 }
6896
6897 return elements;
6898}
6899
6900jQuery.fn.extend({
6901 css: function( name, value ) {
6902 return jQuery.access( this, function( elem, name, value ) {
6903 var len, styles,
6904 map = {},
6905 i = 0;
6906
6907 if ( jQuery.isArray( name ) ) {
6908 styles = getStyles( elem );
6909 len = name.length;
6910
6911 for ( ; i < len; i++ ) {
6912 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6913 }
6914
6915 return map;
6916 }
6917
6918 return value !== undefined ?
6919 jQuery.style( elem, name, value ) :
6920 jQuery.css( elem, name );
6921 }, name, value, arguments.length > 1 );
6922 },
6923 show: function() {
6924 return showHide( this, true );
6925 },
6926 hide: function() {
6927 return showHide( this );
6928 },
6929 toggle: function( state ) {
6930 if ( typeof state === "boolean" ) {
6931 return state ? this.show() : this.hide();
6932 }
6933
6934 return this.each(function() {
6935 if ( isHidden( this ) ) {
6936 jQuery( this ).show();
6937 } else {
6938 jQuery( this ).hide();
6939 }
6940 });
6941 }
6942});
6943
6944jQuery.extend({
6945 // Add in style property hooks for overriding the default
6946 // behavior of getting and setting a style property
6947 cssHooks: {
6948 opacity: {
6949 get: function( elem, computed ) {
6950 if ( computed ) {
6951 // We should always get a number back from opacity
6952 var ret = curCSS( elem, "opacity" );
6953 return ret === "" ? "1" : ret;
6954 }
6955 }
6956 }
6957 },
6958
6959 // Don't automatically add "px" to these possibly-unitless properties
6960 cssNumber: {
6961 "columnCount": true,
6962 "fillOpacity": true,
6963 "fontWeight": true,
6964 "lineHeight": true,
6965 "opacity": true,
6966 "order": true,
6967 "orphans": true,
6968 "widows": true,
6969 "zIndex": true,
6970 "zoom": true
6971 },
6972
6973 // Add in properties whose names you wish to fix before
6974 // setting or getting the value
6975 cssProps: {
6976 // normalize float css property
6977 "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
6978 },
6979
6980 // Get and set the style property on a DOM Node
6981 style: function( elem, name, value, extra ) {
6982 // Don't set styles on text and comment nodes
6983 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6984 return;
6985 }
6986
6987 // Make sure that we're working with the right name
6988 var ret, type, hooks,
6989 origName = jQuery.camelCase( name ),
6990 style = elem.style;
6991
6992 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6993
6994 // gets hook for the prefixed version
6995 // followed by the unprefixed version
6996 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6997
6998 // Check if we're setting a value
6999 if ( value !== undefined ) {
7000 type = typeof value;
7001
7002 // convert relative number strings (+= or -=) to relative numbers. #7345
7003 if ( type === "string" && (ret = rrelNum.exec( value )) ) {
7004 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
7005 // Fixes bug #9237
7006 type = "number";
7007 }
7008
7009 // Make sure that NaN and null values aren't set. See: #7116
7010 if ( value == null || type === "number" && isNaN( value ) ) {
7011 return;
7012 }
7013
7014 // If a number was passed in, add 'px' to the (except for certain CSS properties)
7015 if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
7016 value += "px";
7017 }
7018
7019 // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
7020 // but it would mean to define eight (for every problematic property) identical functions
7021 if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
7022 style[ name ] = "inherit";
7023 }
7024
7025 // If a hook was provided, use that value, otherwise just set the specified value
7026 if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
7027
7028 // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
7029 // Fixes bug #5509
7030 try {
7031 style[ name ] = value;
7032 } catch(e) {}
7033 }
7034
7035 } else {
7036 // If a hook was provided get the non-computed value from there
7037 if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
7038 return ret;
7039 }
7040
7041 // Otherwise just get the value from the style object
7042 return style[ name ];
7043 }
7044 },
7045
7046 css: function( elem, name, extra, styles ) {
7047 var num, val, hooks,
7048 origName = jQuery.camelCase( name );
7049
7050 // Make sure that we're working with the right name
7051 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
7052
7053 // gets hook for the prefixed version
7054 // followed by the unprefixed version
7055 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
7056
7057 // If a hook was provided get the computed value from there
7058 if ( hooks && "get" in hooks ) {
7059 val = hooks.get( elem, true, extra );
7060 }
7061
7062 // Otherwise, if a way to get the computed value exists, use that
7063 if ( val === undefined ) {
7064 val = curCSS( elem, name, styles );
7065 }
7066
7067 //convert "normal" to computed value
7068 if ( val === "normal" && name in cssNormalTransform ) {
7069 val = cssNormalTransform[ name ];
7070 }
7071
7072 // Return, converting to number if forced or a qualifier was provided and val looks numeric
7073 if ( extra === "" || extra ) {
7074 num = parseFloat( val );
7075 return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
7076 }
7077 return val;
7078 }
7079});
7080
7081// NOTE: we've included the "window" in window.getComputedStyle
7082// because jsdom on node.js will break without it.
7083if ( window.getComputedStyle ) {
7084 getStyles = function( elem ) {
7085 return window.getComputedStyle( elem, null );
7086 };
7087
7088 curCSS = function( elem, name, _computed ) {
7089 var width, minWidth, maxWidth,
7090 computed = _computed || getStyles( elem ),
7091
7092 // getPropertyValue is only needed for .css('filter') in IE9, see #12537
7093 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
7094 style = elem.style;
7095
7096 if ( computed ) {
7097
7098 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
7099 ret = jQuery.style( elem, name );
7100 }
7101
7102 // A tribute to the "awesome hack by Dean Edwards"
7103 // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
7104 // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
7105 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
7106 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
7107
7108 // Remember the original values
7109 width = style.width;
7110 minWidth = style.minWidth;
7111 maxWidth = style.maxWidth;
7112
7113 // Put in the new values to get a computed value out
7114 style.minWidth = style.maxWidth = style.width = ret;
7115 ret = computed.width;
7116
7117 // Revert the changed values
7118 style.width = width;
7119 style.minWidth = minWidth;
7120 style.maxWidth = maxWidth;
7121 }
7122 }
7123
7124 return ret;
7125 };
7126} else if ( document.documentElement.currentStyle ) {
7127 getStyles = function( elem ) {
7128 return elem.currentStyle;
7129 };
7130
7131 curCSS = function( elem, name, _computed ) {
7132 var left, rs, rsLeft,
7133 computed = _computed || getStyles( elem ),
7134 ret = computed ? computed[ name ] : undefined,
7135 style = elem.style;
7136
7137 // Avoid setting ret to empty string here
7138 // so we don't default to auto
7139 if ( ret == null && style && style[ name ] ) {
7140 ret = style[ name ];
7141 }
7142
7143 // From the awesome hack by Dean Edwards
7144 // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
7145
7146 // If we're not dealing with a regular pixel number
7147 // but a number that has a weird ending, we need to convert it to pixels
7148 // but not position css attributes, as those are proportional to the parent element instead
7149 // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
7150 if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
7151
7152 // Remember the original values
7153 left = style.left;
7154 rs = elem.runtimeStyle;
7155 rsLeft = rs && rs.left;
7156
7157 // Put in the new values to get a computed value out
7158 if ( rsLeft ) {
7159 rs.left = elem.currentStyle.left;
7160 }
7161 style.left = name === "fontSize" ? "1em" : ret;
7162 ret = style.pixelLeft + "px";
7163
7164 // Revert the changed values
7165 style.left = left;
7166 if ( rsLeft ) {
7167 rs.left = rsLeft;
7168 }
7169 }
7170
7171 return ret === "" ? "auto" : ret;
7172 };
7173}
7174
7175function setPositiveNumber( elem, value, subtract ) {
7176 var matches = rnumsplit.exec( value );
7177 return matches ?
7178 // Guard against undefined "subtract", e.g., when used as in cssHooks
7179 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
7180 value;
7181}
7182
7183function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
7184 var i = extra === ( isBorderBox ? "border" : "content" ) ?
7185 // If we already have the right measurement, avoid augmentation
7186 4 :
7187 // Otherwise initialize for horizontal or vertical properties
7188 name === "width" ? 1 : 0,
7189
7190 val = 0;
7191
7192 for ( ; i < 4; i += 2 ) {
7193 // both box models exclude margin, so add it if we want it
7194 if ( extra === "margin" ) {
7195 val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
7196 }
7197
7198 if ( isBorderBox ) {
7199 // border-box includes padding, so remove it if we want content
7200 if ( extra === "content" ) {
7201 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7202 }
7203
7204 // at this point, extra isn't border nor margin, so remove border
7205 if ( extra !== "margin" ) {
7206 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7207 }
7208 } else {
7209 // at this point, extra isn't content, so add padding
7210 val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7211
7212 // at this point, extra isn't content nor padding, so add border
7213 if ( extra !== "padding" ) {
7214 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7215 }
7216 }
7217 }
7218
7219 return val;
7220}
7221
7222function getWidthOrHeight( elem, name, extra ) {
7223
7224 // Start with offset property, which is equivalent to the border-box value
7225 var valueIsBorderBox = true,
7226 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7227 styles = getStyles( elem ),
7228 isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
7229
7230 // some non-html elements return undefined for offsetWidth, so check for null/undefined
7231 // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
7232 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
7233 if ( val <= 0 || val == null ) {
7234 // Fall back to computed then uncomputed css if necessary
7235 val = curCSS( elem, name, styles );
7236 if ( val < 0 || val == null ) {
7237 val = elem.style[ name ];
7238 }
7239
7240 // Computed unit is not pixels. Stop here and return.
7241 if ( rnumnonpx.test(val) ) {
7242 return val;
7243 }
7244
7245 // we need the check for style in case a browser which returns unreliable values
7246 // for getComputedStyle silently falls back to the reliable elem.style
7247 valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
7248
7249 // Normalize "", auto, and prepare for extra
7250 val = parseFloat( val ) || 0;
7251 }
7252
7253 // use the active box-sizing model to add/subtract irrelevant styles
7254 return ( val +
7255 augmentWidthOrHeight(
7256 elem,
7257 name,
7258 extra || ( isBorderBox ? "border" : "content" ),
7259 valueIsBorderBox,
7260 styles
7261 )
7262 ) + "px";
7263}
7264
7265// Try to determine the default display value of an element
7266function css_defaultDisplay( nodeName ) {
7267 var doc = document,
7268 display = elemdisplay[ nodeName ];
7269
7270 if ( !display ) {
7271 display = actualDisplay( nodeName, doc );
7272
7273 // If the simple way fails, read from inside an iframe
7274 if ( display === "none" || !display ) {
7275 // Use the already-created iframe if possible
7276 iframe = ( iframe ||
7277 jQuery("<iframe frameborder='0' width='0' height='0'/>")
7278 .css( "cssText", "display:block !important" )
7279 ).appendTo( doc.documentElement );
7280
7281 // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
7282 doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
7283 doc.write("<!doctype html><html><body>");
7284 doc.close();
7285
7286 display = actualDisplay( nodeName, doc );
7287 iframe.detach();
7288 }
7289
7290 // Store the correct default display
7291 elemdisplay[ nodeName ] = display;
7292 }
7293
7294 return display;
7295}
7296
7297// Called ONLY from within css_defaultDisplay
7298function actualDisplay( name, doc ) {
7299 var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
7300 display = jQuery.css( elem[0], "display" );
7301 elem.remove();
7302 return display;
7303}
7304
7305jQuery.each([ "height", "width" ], function( i, name ) {
7306 jQuery.cssHooks[ name ] = {
7307 get: function( elem, computed, extra ) {
7308 if ( computed ) {
7309 // certain elements can have dimension info if we invisibly show them
7310 // however, it must have a current display style that would benefit from this
7311 return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
7312 jQuery.swap( elem, cssShow, function() {
7313 return getWidthOrHeight( elem, name, extra );
7314 }) :
7315 getWidthOrHeight( elem, name, extra );
7316 }
7317 },
7318
7319 set: function( elem, value, extra ) {
7320 var styles = extra && getStyles( elem );
7321 return setPositiveNumber( elem, value, extra ?
7322 augmentWidthOrHeight(
7323 elem,
7324 name,
7325 extra,
7326 jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7327 styles
7328 ) : 0
7329 );
7330 }
7331 };
7332});
7333
7334if ( !jQuery.support.opacity ) {
7335 jQuery.cssHooks.opacity = {
7336 get: function( elem, computed ) {
7337 // IE uses filters for opacity
7338 return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7339 ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7340 computed ? "1" : "";
7341 },
7342
7343 set: function( elem, value ) {
7344 var style = elem.style,
7345 currentStyle = elem.currentStyle,
7346 opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7347 filter = currentStyle && currentStyle.filter || style.filter || "";
7348
7349 // IE has trouble with opacity if it does not have layout
7350 // Force it by setting the zoom level
7351 style.zoom = 1;
7352
7353 // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7354 // if value === "", then remove inline opacity #12685
7355 if ( ( value >= 1 || value === "" ) &&
7356 jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7357 style.removeAttribute ) {
7358
7359 // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7360 // if "filter:" is present at all, clearType is disabled, we want to avoid this
7361 // style.removeAttribute is IE Only, but so apparently is this code path...
7362 style.removeAttribute( "filter" );
7363
7364 // if there is no filter style applied in a css rule or unset inline opacity, we are done
7365 if ( value === "" || currentStyle && !currentStyle.filter ) {
7366 return;
7367 }
7368 }
7369
7370 // otherwise, set new filter values
7371 style.filter = ralpha.test( filter ) ?
7372 filter.replace( ralpha, opacity ) :
7373 filter + " " + opacity;
7374 }
7375 };
7376}
7377
7378// These hooks cannot be added until DOM ready because the support test
7379// for it is not run until after DOM ready
7380jQuery(function() {
7381 if ( !jQuery.support.reliableMarginRight ) {
7382 jQuery.cssHooks.marginRight = {
7383 get: function( elem, computed ) {
7384 if ( computed ) {
7385 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7386 // Work around by temporarily setting element display to inline-block
7387 return jQuery.swap( elem, { "display": "inline-block" },
7388 curCSS, [ elem, "marginRight" ] );
7389 }
7390 }
7391 };
7392 }
7393
7394 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
7395 // getComputedStyle returns percent when specified for top/left/bottom/right
7396 // rather than make the css module depend on the offset module, we just check for it here
7397 if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
7398 jQuery.each( [ "top", "left" ], function( i, prop ) {
7399 jQuery.cssHooks[ prop ] = {
7400 get: function( elem, computed ) {
7401 if ( computed ) {
7402 computed = curCSS( elem, prop );
7403 // if curCSS returns percentage, fallback to offset
7404 return rnumnonpx.test( computed ) ?
7405 jQuery( elem ).position()[ prop ] + "px" :
7406 computed;
7407 }
7408 }
7409 };
7410 });
7411 }
7412
7413});
7414
7415if ( jQuery.expr && jQuery.expr.filters ) {
7416 jQuery.expr.filters.hidden = function( elem ) {
7417 // Support: Opera <= 12.12
7418 // Opera reports offsetWidths and offsetHeights less than zero on some elements
7419 return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
7420 (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7421 };
7422
7423 jQuery.expr.filters.visible = function( elem ) {
7424 return !jQuery.expr.filters.hidden( elem );
7425 };
7426}
7427
7428// These hooks are used by animate to expand properties
7429jQuery.each({
7430 margin: "",
7431 padding: "",
7432 border: "Width"
7433}, function( prefix, suffix ) {
7434 jQuery.cssHooks[ prefix + suffix ] = {
7435 expand: function( value ) {
7436 var i = 0,
7437 expanded = {},
7438
7439 // assumes a single number if not a string
7440 parts = typeof value === "string" ? value.split(" ") : [ value ];
7441
7442 for ( ; i < 4; i++ ) {
7443 expanded[ prefix + cssExpand[ i ] + suffix ] =
7444 parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7445 }
7446
7447 return expanded;
7448 }
7449 };
7450
7451 if ( !rmargin.test( prefix ) ) {
7452 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7453 }
7454});
7455var r20 = /%20/g,
7456 rbracket = /\[\]$/,
7457 rCRLF = /\r?\n/g,
7458 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
7459 rsubmittable = /^(?:input|select|textarea|keygen)/i;
7460
7461jQuery.fn.extend({
7462 serialize: function() {
7463 return jQuery.param( this.serializeArray() );
7464 },
7465 serializeArray: function() {
7466 return this.map(function(){
7467 // Can add propHook for "elements" to filter or add form elements
7468 var elements = jQuery.prop( this, "elements" );
7469 return elements ? jQuery.makeArray( elements ) : this;
7470 })
7471 .filter(function(){
7472 var type = this.type;
7473 // Use .is(":disabled") so that fieldset[disabled] works
7474 return this.name && !jQuery( this ).is( ":disabled" ) &&
7475 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
7476 ( this.checked || !manipulation_rcheckableType.test( type ) );
7477 })
7478 .map(function( i, elem ){
7479 var val = jQuery( this ).val();
7480
7481 return val == null ?
7482 null :
7483 jQuery.isArray( val ) ?
7484 jQuery.map( val, function( val ){
7485 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7486 }) :
7487 { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7488 }).get();
7489 }
7490});
7491
7492//Serialize an array of form elements or a set of
7493//key/values into a query string
7494jQuery.param = function( a, traditional ) {
7495 var prefix,
7496 s = [],
7497 add = function( key, value ) {
7498 // If value is a function, invoke it and return its value
7499 value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
7500 s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
7501 };
7502
7503 // Set traditional to true for jQuery <= 1.3.2 behavior.
7504 if ( traditional === undefined ) {
7505 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
7506 }
7507
7508 // If an array was passed in, assume that it is an array of form elements.
7509 if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
7510 // Serialize the form elements
7511 jQuery.each( a, function() {
7512 add( this.name, this.value );
7513 });
7514
7515 } else {
7516 // If traditional, encode the "old" way (the way 1.3.2 or older
7517 // did it), otherwise encode params recursively.
7518 for ( prefix in a ) {
7519 buildParams( prefix, a[ prefix ], traditional, add );
7520 }
7521 }
7522
7523 // Return the resulting serialization
7524 return s.join( "&" ).replace( r20, "+" );
7525};
7526
7527function buildParams( prefix, obj, traditional, add ) {
7528 var name;
7529
7530 if ( jQuery.isArray( obj ) ) {
7531 // Serialize array item.
7532 jQuery.each( obj, function( i, v ) {
7533 if ( traditional || rbracket.test( prefix ) ) {
7534 // Treat each array item as a scalar.
7535 add( prefix, v );
7536
7537 } else {
7538 // Item is non-scalar (array or object), encode its numeric index.
7539 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
7540 }
7541 });
7542
7543 } else if ( !traditional && jQuery.type( obj ) === "object" ) {
7544 // Serialize object item.
7545 for ( name in obj ) {
7546 buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
7547 }
7548
7549 } else {
7550 // Serialize scalar item.
7551 add( prefix, obj );
7552 }
7553}
7554jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7555 "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7556 "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7557
7558 // Handle event binding
7559 jQuery.fn[ name ] = function( data, fn ) {
7560 return arguments.length > 0 ?
7561 this.on( name, null, data, fn ) :
7562 this.trigger( name );
7563 };
7564});
7565
7566jQuery.fn.extend({
7567 hover: function( fnOver, fnOut ) {
7568 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7569 },
7570
7571 bind: function( types, data, fn ) {
7572 return this.on( types, null, data, fn );
7573 },
7574 unbind: function( types, fn ) {
7575 return this.off( types, null, fn );
7576 },
7577
7578 delegate: function( selector, types, data, fn ) {
7579 return this.on( types, selector, data, fn );
7580 },
7581 undelegate: function( selector, types, fn ) {
7582 // ( namespace ) or ( selector, types [, fn] )
7583 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
7584 }
7585});
7586var
7587 // Document location
7588 ajaxLocParts,
7589 ajaxLocation,
7590 ajax_nonce = jQuery.now(),
7591
7592 ajax_rquery = /\?/,
7593 rhash = /#.*$/,
7594 rts = /([?&])_=[^&]*/,
7595 rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7596 // #7653, #8125, #8152: local protocol detection
7597 rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7598 rnoContent = /^(?:GET|HEAD)$/,
7599 rprotocol = /^\/\//,
7600 rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
7601
7602 // Keep a copy of the old load method
7603 _load = jQuery.fn.load,
7604
7605 /* Prefilters
7606 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7607 * 2) These are called:
7608 * - BEFORE asking for a transport
7609 * - AFTER param serialization (s.data is a string if s.processData is true)
7610 * 3) key is the dataType
7611 * 4) the catchall symbol "*" can be used
7612 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7613 */
7614 prefilters = {},
7615
7616 /* Transports bindings
7617 * 1) key is the dataType
7618 * 2) the catchall symbol "*" can be used
7619 * 3) selection will start with transport dataType and THEN go to "*" if needed
7620 */
7621 transports = {},
7622
7623 // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7624 allTypes = "*/".concat("*");
7625
7626// #8138, IE may throw an exception when accessing
7627// a field from window.location if document.domain has been set
7628try {
7629 ajaxLocation = location.href;
7630} catch( e ) {
7631 // Use the href attribute of an A element
7632 // since IE will modify it given document.location
7633 ajaxLocation = document.createElement( "a" );
7634 ajaxLocation.href = "";
7635 ajaxLocation = ajaxLocation.href;
7636}
7637
7638// Segment location into parts
7639ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7640
7641// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7642function addToPrefiltersOrTransports( structure ) {
7643
7644 // dataTypeExpression is optional and defaults to "*"
7645 return function( dataTypeExpression, func ) {
7646
7647 if ( typeof dataTypeExpression !== "string" ) {
7648 func = dataTypeExpression;
7649 dataTypeExpression = "*";
7650 }
7651
7652 var dataType,
7653 i = 0,
7654 dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
7655
7656 if ( jQuery.isFunction( func ) ) {
7657 // For each dataType in the dataTypeExpression
7658 while ( (dataType = dataTypes[i++]) ) {
7659 // Prepend if requested
7660 if ( dataType[0] === "+" ) {
7661 dataType = dataType.slice( 1 ) || "*";
7662 (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7663
7664 // Otherwise append
7665 } else {
7666 (structure[ dataType ] = structure[ dataType ] || []).push( func );
7667 }
7668 }
7669 }
7670 };
7671}
7672
7673// Base inspection function for prefilters and transports
7674function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7675
7676 var inspected = {},
7677 seekingTransport = ( structure === transports );
7678
7679 function inspect( dataType ) {
7680 var selected;
7681 inspected[ dataType ] = true;
7682 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7683 var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7684 if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7685 options.dataTypes.unshift( dataTypeOrTransport );
7686 inspect( dataTypeOrTransport );
7687 return false;
7688 } else if ( seekingTransport ) {
7689 return !( selected = dataTypeOrTransport );
7690 }
7691 });
7692 return selected;
7693 }
7694
7695 return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7696}
7697
7698// A special extend for ajax options
7699// that takes "flat" options (not to be deep extended)
7700// Fixes #9887
7701function ajaxExtend( target, src ) {
7702 var deep, key,
7703 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7704
7705 for ( key in src ) {
7706 if ( src[ key ] !== undefined ) {
7707 ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7708 }
7709 }
7710 if ( deep ) {
7711 jQuery.extend( true, target, deep );
7712 }
7713
7714 return target;
7715}
7716
7717jQuery.fn.load = function( url, params, callback ) {
7718 if ( typeof url !== "string" && _load ) {
7719 return _load.apply( this, arguments );
7720 }
7721
7722 var selector, response, type,
7723 self = this,
7724 off = url.indexOf(" ");
7725
7726 if ( off >= 0 ) {
7727 selector = url.slice( off, url.length );
7728 url = url.slice( 0, off );
7729 }
7730
7731 // If it's a function
7732 if ( jQuery.isFunction( params ) ) {
7733
7734 // We assume that it's the callback
7735 callback = params;
7736 params = undefined;
7737
7738 // Otherwise, build a param string
7739 } else if ( params && typeof params === "object" ) {
7740 type = "POST";
7741 }
7742
7743 // If we have elements to modify, make the request
7744 if ( self.length > 0 ) {
7745 jQuery.ajax({
7746 url: url,
7747
7748 // if "type" variable is undefined, then "GET" method will be used
7749 type: type,
7750 dataType: "html",
7751 data: params
7752 }).done(function( responseText ) {
7753
7754 // Save response for use in complete callback
7755 response = arguments;
7756
7757 self.html( selector ?
7758
7759 // If a selector was specified, locate the right elements in a dummy div
7760 // Exclude scripts to avoid IE 'Permission Denied' errors
7761 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
7762
7763 // Otherwise use the full result
7764 responseText );
7765
7766 }).complete( callback && function( jqXHR, status ) {
7767 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
7768 });
7769 }
7770
7771 return this;
7772};
7773
7774// Attach a bunch of functions for handling common AJAX events
7775jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
7776 jQuery.fn[ type ] = function( fn ){
7777 return this.on( type, fn );
7778 };
7779});
7780
7781jQuery.extend({
7782
7783 // Counter for holding the number of active queries
7784 active: 0,
7785
7786 // Last-Modified header cache for next request
7787 lastModified: {},
7788 etag: {},
7789
7790 ajaxSettings: {
7791 url: ajaxLocation,
7792 type: "GET",
7793 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7794 global: true,
7795 processData: true,
7796 async: true,
7797 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7798 /*
7799 timeout: 0,
7800 data: null,
7801 dataType: null,
7802 username: null,
7803 password: null,
7804 cache: null,
7805 throws: false,
7806 traditional: false,
7807 headers: {},
7808 */
7809
7810 accepts: {
7811 "*": allTypes,
7812 text: "text/plain",
7813 html: "text/html",
7814 xml: "application/xml, text/xml",
7815 json: "application/json, text/javascript"
7816 },
7817
7818 contents: {
7819 xml: /xml/,
7820 html: /html/,
7821 json: /json/
7822 },
7823
7824 responseFields: {
7825 xml: "responseXML",
7826 text: "responseText",
7827 json: "responseJSON"
7828 },
7829
7830 // Data converters
7831 // Keys separate source (or catchall "*") and destination types with a single space
7832 converters: {
7833
7834 // Convert anything to text
7835 "* text": String,
7836
7837 // Text to html (true = no transformation)
7838 "text html": true,
7839
7840 // Evaluate text as a json expression
7841 "text json": jQuery.parseJSON,
7842
7843 // Parse text as xml
7844 "text xml": jQuery.parseXML
7845 },
7846
7847 // For options that shouldn't be deep extended:
7848 // you can add your own custom options here if
7849 // and when you create one that shouldn't be
7850 // deep extended (see ajaxExtend)
7851 flatOptions: {
7852 url: true,
7853 context: true
7854 }
7855 },
7856
7857 // Creates a full fledged settings object into target
7858 // with both ajaxSettings and settings fields.
7859 // If target is omitted, writes into ajaxSettings.
7860 ajaxSetup: function( target, settings ) {
7861 return settings ?
7862
7863 // Building a settings object
7864 ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7865
7866 // Extending ajaxSettings
7867 ajaxExtend( jQuery.ajaxSettings, target );
7868 },
7869
7870 ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7871 ajaxTransport: addToPrefiltersOrTransports( transports ),
7872
7873 // Main method
7874 ajax: function( url, options ) {
7875
7876 // If url is an object, simulate pre-1.5 signature
7877 if ( typeof url === "object" ) {
7878 options = url;
7879 url = undefined;
7880 }
7881
7882 // Force options to be an object
7883 options = options || {};
7884
7885 var // Cross-domain detection vars
7886 parts,
7887 // Loop variable
7888 i,
7889 // URL without anti-cache param
7890 cacheURL,
7891 // Response headers as string
7892 responseHeadersString,
7893 // timeout handle
7894 timeoutTimer,
7895
7896 // To know if global events are to be dispatched
7897 fireGlobals,
7898
7899 transport,
7900 // Response headers
7901 responseHeaders,
7902 // Create the final options object
7903 s = jQuery.ajaxSetup( {}, options ),
7904 // Callbacks context
7905 callbackContext = s.context || s,
7906 // Context for global events is callbackContext if it is a DOM node or jQuery collection
7907 globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7908 jQuery( callbackContext ) :
7909 jQuery.event,
7910 // Deferreds
7911 deferred = jQuery.Deferred(),
7912 completeDeferred = jQuery.Callbacks("once memory"),
7913 // Status-dependent callbacks
7914 statusCode = s.statusCode || {},
7915 // Headers (they are sent all at once)
7916 requestHeaders = {},
7917 requestHeadersNames = {},
7918 // The jqXHR state
7919 state = 0,
7920 // Default abort message
7921 strAbort = "canceled",
7922 // Fake xhr
7923 jqXHR = {
7924 readyState: 0,
7925
7926 // Builds headers hashtable if needed
7927 getResponseHeader: function( key ) {
7928 var match;
7929 if ( state === 2 ) {
7930 if ( !responseHeaders ) {
7931 responseHeaders = {};
7932 while ( (match = rheaders.exec( responseHeadersString )) ) {
7933 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7934 }
7935 }
7936 match = responseHeaders[ key.toLowerCase() ];
7937 }
7938 return match == null ? null : match;
7939 },
7940
7941 // Raw string
7942 getAllResponseHeaders: function() {
7943 return state === 2 ? responseHeadersString : null;
7944 },
7945
7946 // Caches the header
7947 setRequestHeader: function( name, value ) {
7948 var lname = name.toLowerCase();
7949 if ( !state ) {
7950 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7951 requestHeaders[ name ] = value;
7952 }
7953 return this;
7954 },
7955
7956 // Overrides response content-type header
7957 overrideMimeType: function( type ) {
7958 if ( !state ) {
7959 s.mimeType = type;
7960 }
7961 return this;
7962 },
7963
7964 // Status-dependent callbacks
7965 statusCode: function( map ) {
7966 var code;
7967 if ( map ) {
7968 if ( state < 2 ) {
7969 for ( code in map ) {
7970 // Lazy-add the new callback in a way that preserves old ones
7971 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7972 }
7973 } else {
7974 // Execute the appropriate callbacks
7975 jqXHR.always( map[ jqXHR.status ] );
7976 }
7977 }
7978 return this;
7979 },
7980
7981 // Cancel the request
7982 abort: function( statusText ) {
7983 var finalText = statusText || strAbort;
7984 if ( transport ) {
7985 transport.abort( finalText );
7986 }
7987 done( 0, finalText );
7988 return this;
7989 }
7990 };
7991
7992 // Attach deferreds
7993 deferred.promise( jqXHR ).complete = completeDeferred.add;
7994 jqXHR.success = jqXHR.done;
7995 jqXHR.error = jqXHR.fail;
7996
7997 // Remove hash character (#7531: and string promotion)
7998 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
7999 // Handle falsy url in the settings object (#10093: consistency with old signature)
8000 // We also use the url parameter if available
8001 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8002
8003 // Alias method option to type as per ticket #12004
8004 s.type = options.method || options.type || s.method || s.type;
8005
8006 // Extract dataTypes list
8007 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
8008
8009 // A cross-domain request is in order when we have a protocol:host:port mismatch
8010 if ( s.crossDomain == null ) {
8011 parts = rurl.exec( s.url.toLowerCase() );
8012 s.crossDomain = !!( parts &&
8013 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
8014 ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
8015 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
8016 );
8017 }
8018
8019 // Convert data if not already a string
8020 if ( s.data && s.processData && typeof s.data !== "string" ) {
8021 s.data = jQuery.param( s.data, s.traditional );
8022 }
8023
8024 // Apply prefilters
8025 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8026
8027 // If request was aborted inside a prefilter, stop there
8028 if ( state === 2 ) {
8029 return jqXHR;
8030 }
8031
8032 // We can fire global events as of now if asked to
8033 fireGlobals = s.global;
8034
8035 // Watch for a new set of requests
8036 if ( fireGlobals && jQuery.active++ === 0 ) {
8037 jQuery.event.trigger("ajaxStart");
8038 }
8039
8040 // Uppercase the type
8041 s.type = s.type.toUpperCase();
8042
8043 // Determine if request has content
8044 s.hasContent = !rnoContent.test( s.type );
8045
8046 // Save the URL in case we're toying with the If-Modified-Since
8047 // and/or If-None-Match header later on
8048 cacheURL = s.url;
8049
8050 // More options handling for requests with no content
8051 if ( !s.hasContent ) {
8052
8053 // If data is available, append data to url
8054 if ( s.data ) {
8055 cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8056 // #9682: remove data so that it's not used in an eventual retry
8057 delete s.data;
8058 }
8059
8060 // Add anti-cache in url if needed
8061 if ( s.cache === false ) {
8062 s.url = rts.test( cacheURL ) ?
8063
8064 // If there is already a '_' parameter, set its value
8065 cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
8066
8067 // Otherwise add one to the end
8068 cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
8069 }
8070 }
8071
8072 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8073 if ( s.ifModified ) {
8074 if ( jQuery.lastModified[ cacheURL ] ) {
8075 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8076 }
8077 if ( jQuery.etag[ cacheURL ] ) {
8078 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8079 }
8080 }
8081
8082 // Set the correct header, if data is being sent
8083 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8084 jqXHR.setRequestHeader( "Content-Type", s.contentType );
8085 }
8086
8087 // Set the Accepts header for the server, depending on the dataType
8088 jqXHR.setRequestHeader(
8089 "Accept",
8090 s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8091 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8092 s.accepts[ "*" ]
8093 );
8094
8095 // Check for headers option
8096 for ( i in s.headers ) {
8097 jqXHR.setRequestHeader( i, s.headers[ i ] );
8098 }
8099
8100 // Allow custom headers/mimetypes and early abort
8101 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8102 // Abort if not done already and return
8103 return jqXHR.abort();
8104 }
8105
8106 // aborting is no longer a cancellation
8107 strAbort = "abort";
8108
8109 // Install callbacks on deferreds
8110 for ( i in { success: 1, error: 1, complete: 1 } ) {
8111 jqXHR[ i ]( s[ i ] );
8112 }
8113
8114 // Get transport
8115 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8116
8117 // If no transport, we auto-abort
8118 if ( !transport ) {
8119 done( -1, "No Transport" );
8120 } else {
8121 jqXHR.readyState = 1;
8122
8123 // Send global event
8124 if ( fireGlobals ) {
8125 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8126 }
8127 // Timeout
8128 if ( s.async && s.timeout > 0 ) {
8129 timeoutTimer = setTimeout(function() {
8130 jqXHR.abort("timeout");
8131 }, s.timeout );
8132 }
8133
8134 try {
8135 state = 1;
8136 transport.send( requestHeaders, done );
8137 } catch ( e ) {
8138 // Propagate exception as error if not done
8139 if ( state < 2 ) {
8140 done( -1, e );
8141 // Simply rethrow otherwise
8142 } else {
8143 throw e;
8144 }
8145 }
8146 }
8147
8148 // Callback for when everything is done
8149 function done( status, nativeStatusText, responses, headers ) {
8150 var isSuccess, success, error, response, modified,
8151 statusText = nativeStatusText;
8152
8153 // Called once
8154 if ( state === 2 ) {
8155 return;
8156 }
8157
8158 // State is "done" now
8159 state = 2;
8160
8161 // Clear timeout if it exists
8162 if ( timeoutTimer ) {
8163 clearTimeout( timeoutTimer );
8164 }
8165
8166 // Dereference transport for early garbage collection
8167 // (no matter how long the jqXHR object will be used)
8168 transport = undefined;
8169
8170 // Cache response headers
8171 responseHeadersString = headers || "";
8172
8173 // Set readyState
8174 jqXHR.readyState = status > 0 ? 4 : 0;
8175
8176 // Determine if successful
8177 isSuccess = status >= 200 && status < 300 || status === 304;
8178
8179 // Get response data
8180 if ( responses ) {
8181 response = ajaxHandleResponses( s, jqXHR, responses );
8182 }
8183
8184 // Convert no matter what (that way responseXXX fields are always set)
8185 response = ajaxConvert( s, response, jqXHR, isSuccess );
8186
8187 // If successful, handle type chaining
8188 if ( isSuccess ) {
8189
8190 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8191 if ( s.ifModified ) {
8192 modified = jqXHR.getResponseHeader("Last-Modified");
8193 if ( modified ) {
8194 jQuery.lastModified[ cacheURL ] = modified;
8195 }
8196 modified = jqXHR.getResponseHeader("etag");
8197 if ( modified ) {
8198 jQuery.etag[ cacheURL ] = modified;
8199 }
8200 }
8201
8202 // if no content
8203 if ( status === 204 || s.type === "HEAD" ) {
8204 statusText = "nocontent";
8205
8206 // if not modified
8207 } else if ( status === 304 ) {
8208 statusText = "notmodified";
8209
8210 // If we have data, let's convert it
8211 } else {
8212 statusText = response.state;
8213 success = response.data;
8214 error = response.error;
8215 isSuccess = !error;
8216 }
8217 } else {
8218 // We extract error from statusText
8219 // then normalize statusText and status for non-aborts
8220 error = statusText;
8221 if ( status || !statusText ) {
8222 statusText = "error";
8223 if ( status < 0 ) {
8224 status = 0;
8225 }
8226 }
8227 }
8228
8229 // Set data for the fake xhr object
8230 jqXHR.status = status;
8231 jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8232
8233 // Success/Error
8234 if ( isSuccess ) {
8235 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8236 } else {
8237 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8238 }
8239
8240 // Status-dependent callbacks
8241 jqXHR.statusCode( statusCode );
8242 statusCode = undefined;
8243
8244 if ( fireGlobals ) {
8245 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8246 [ jqXHR, s, isSuccess ? success : error ] );
8247 }
8248
8249 // Complete
8250 completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8251
8252 if ( fireGlobals ) {
8253 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8254 // Handle the global AJAX counter
8255 if ( !( --jQuery.active ) ) {
8256 jQuery.event.trigger("ajaxStop");
8257 }
8258 }
8259 }
8260
8261 return jqXHR;
8262 },
8263
8264 getJSON: function( url, data, callback ) {
8265 return jQuery.get( url, data, callback, "json" );
8266 },
8267
8268 getScript: function( url, callback ) {
8269 return jQuery.get( url, undefined, callback, "script" );
8270 }
8271});
8272
8273jQuery.each( [ "get", "post" ], function( i, method ) {
8274 jQuery[ method ] = function( url, data, callback, type ) {
8275 // shift arguments if data argument was omitted
8276 if ( jQuery.isFunction( data ) ) {
8277 type = type || callback;
8278 callback = data;
8279 data = undefined;
8280 }
8281
8282 return jQuery.ajax({
8283 url: url,
8284 type: method,
8285 dataType: type,
8286 data: data,
8287 success: callback
8288 });
8289 };
8290});
8291
8292/* Handles responses to an ajax request:
8293 * - finds the right dataType (mediates between content-type and expected dataType)
8294 * - returns the corresponding response
8295 */
8296function ajaxHandleResponses( s, jqXHR, responses ) {
8297 var firstDataType, ct, finalDataType, type,
8298 contents = s.contents,
8299 dataTypes = s.dataTypes;
8300
8301 // Remove auto dataType and get content-type in the process
8302 while( dataTypes[ 0 ] === "*" ) {
8303 dataTypes.shift();
8304 if ( ct === undefined ) {
8305 ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
8306 }
8307 }
8308
8309 // Check if we're dealing with a known content-type
8310 if ( ct ) {
8311 for ( type in contents ) {
8312 if ( contents[ type ] && contents[ type ].test( ct ) ) {
8313 dataTypes.unshift( type );
8314 break;
8315 }
8316 }
8317 }
8318
8319 // Check to see if we have a response for the expected dataType
8320 if ( dataTypes[ 0 ] in responses ) {
8321 finalDataType = dataTypes[ 0 ];
8322 } else {
8323 // Try convertible dataTypes
8324 for ( type in responses ) {
8325 if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8326 finalDataType = type;
8327 break;
8328 }
8329 if ( !firstDataType ) {
8330 firstDataType = type;
8331 }
8332 }
8333 // Or just use first one
8334 finalDataType = finalDataType || firstDataType;
8335 }
8336
8337 // If we found a dataType
8338 // We add the dataType to the list if needed
8339 // and return the corresponding response
8340 if ( finalDataType ) {
8341 if ( finalDataType !== dataTypes[ 0 ] ) {
8342 dataTypes.unshift( finalDataType );
8343 }
8344 return responses[ finalDataType ];
8345 }
8346}
8347
8348/* Chain conversions given the request and the original response
8349 * Also sets the responseXXX fields on the jqXHR instance
8350 */
8351function ajaxConvert( s, response, jqXHR, isSuccess ) {
8352 var conv2, current, conv, tmp, prev,
8353 converters = {},
8354 // Work with a copy of dataTypes in case we need to modify it for conversion
8355 dataTypes = s.dataTypes.slice();
8356
8357 // Create converters map with lowercased keys
8358 if ( dataTypes[ 1 ] ) {
8359 for ( conv in s.converters ) {
8360 converters[ conv.toLowerCase() ] = s.converters[ conv ];
8361 }
8362 }
8363
8364 current = dataTypes.shift();
8365
8366 // Convert to each sequential dataType
8367 while ( current ) {
8368
8369 if ( s.responseFields[ current ] ) {
8370 jqXHR[ s.responseFields[ current ] ] = response;
8371 }
8372
8373 // Apply the dataFilter if provided
8374 if ( !prev && isSuccess && s.dataFilter ) {
8375 response = s.dataFilter( response, s.dataType );
8376 }
8377
8378 prev = current;
8379 current = dataTypes.shift();
8380
8381 if ( current ) {
8382
8383 // There's only work to do if current dataType is non-auto
8384 if ( current === "*" ) {
8385
8386 current = prev;
8387
8388 // Convert response if prev dataType is non-auto and differs from current
8389 } else if ( prev !== "*" && prev !== current ) {
8390
8391 // Seek a direct converter
8392 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8393
8394 // If none found, seek a pair
8395 if ( !conv ) {
8396 for ( conv2 in converters ) {
8397
8398 // If conv2 outputs current
8399 tmp = conv2.split( " " );
8400 if ( tmp[ 1 ] === current ) {
8401
8402 // If prev can be converted to accepted input
8403 conv = converters[ prev + " " + tmp[ 0 ] ] ||
8404 converters[ "* " + tmp[ 0 ] ];
8405 if ( conv ) {
8406 // Condense equivalence converters
8407 if ( conv === true ) {
8408 conv = converters[ conv2 ];
8409
8410 // Otherwise, insert the intermediate dataType
8411 } else if ( converters[ conv2 ] !== true ) {
8412 current = tmp[ 0 ];
8413 dataTypes.unshift( tmp[ 1 ] );
8414 }
8415 break;
8416 }
8417 }
8418 }
8419 }
8420
8421 // Apply converter (if not an equivalence)
8422 if ( conv !== true ) {
8423
8424 // Unless errors are allowed to bubble, catch and return them
8425 if ( conv && s[ "throws" ] ) {
8426 response = conv( response );
8427 } else {
8428 try {
8429 response = conv( response );
8430 } catch ( e ) {
8431 return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
8432 }
8433 }
8434 }
8435 }
8436 }
8437 }
8438
8439 return { state: "success", data: response };
8440}
8441// Install script dataType
8442jQuery.ajaxSetup({
8443 accepts: {
8444 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8445 },
8446 contents: {
8447 script: /(?:java|ecma)script/
8448 },
8449 converters: {
8450 "text script": function( text ) {
8451 jQuery.globalEval( text );
8452 return text;
8453 }
8454 }
8455});
8456
8457// Handle cache's special case and global
8458jQuery.ajaxPrefilter( "script", function( s ) {
8459 if ( s.cache === undefined ) {
8460 s.cache = false;
8461 }
8462 if ( s.crossDomain ) {
8463 s.type = "GET";
8464 s.global = false;
8465 }
8466});
8467
8468// Bind script tag hack transport
8469jQuery.ajaxTransport( "script", function(s) {
8470
8471 // This transport only deals with cross domain requests
8472 if ( s.crossDomain ) {
8473
8474 var script,
8475 head = document.head || jQuery("head")[0] || document.documentElement;
8476
8477 return {
8478
8479 send: function( _, callback ) {
8480
8481 script = document.createElement("script");
8482
8483 script.async = true;
8484
8485 if ( s.scriptCharset ) {
8486 script.charset = s.scriptCharset;
8487 }
8488
8489 script.src = s.url;
8490
8491 // Attach handlers for all browsers
8492 script.onload = script.onreadystatechange = function( _, isAbort ) {
8493
8494 if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8495
8496 // Handle memory leak in IE
8497 script.onload = script.onreadystatechange = null;
8498
8499 // Remove the script
8500 if ( script.parentNode ) {
8501 script.parentNode.removeChild( script );
8502 }
8503
8504 // Dereference the script
8505 script = null;
8506
8507 // Callback if not abort
8508 if ( !isAbort ) {
8509 callback( 200, "success" );
8510 }
8511 }
8512 };
8513
8514 // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
8515 // Use native DOM manipulation to avoid our domManip AJAX trickery
8516 head.insertBefore( script, head.firstChild );
8517 },
8518
8519 abort: function() {
8520 if ( script ) {
8521 script.onload( undefined, true );
8522 }
8523 }
8524 };
8525 }
8526});
8527var oldCallbacks = [],
8528 rjsonp = /(=)\?(?=&|$)|\?\?/;
8529
8530// Default jsonp settings
8531jQuery.ajaxSetup({
8532 jsonp: "callback",
8533 jsonpCallback: function() {
8534 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
8535 this[ callback ] = true;
8536 return callback;
8537 }
8538});
8539
8540// Detect, normalize options and install callbacks for jsonp requests
8541jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8542
8543 var callbackName, overwritten, responseContainer,
8544 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8545 "url" :
8546 typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8547 );
8548
8549 // Handle iff the expected data type is "jsonp" or we have a parameter to set
8550 if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8551
8552 // Get callback name, remembering preexisting value associated with it
8553 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8554 s.jsonpCallback() :
8555 s.jsonpCallback;
8556
8557 // Insert callback into url or form data
8558 if ( jsonProp ) {
8559 s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8560 } else if ( s.jsonp !== false ) {
8561 s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8562 }
8563
8564 // Use data converter to retrieve json after script execution
8565 s.converters["script json"] = function() {
8566 if ( !responseContainer ) {
8567 jQuery.error( callbackName + " was not called" );
8568 }
8569 return responseContainer[ 0 ];
8570 };
8571
8572 // force json dataType
8573 s.dataTypes[ 0 ] = "json";
8574
8575 // Install callback
8576 overwritten = window[ callbackName ];
8577 window[ callbackName ] = function() {
8578 responseContainer = arguments;
8579 };
8580
8581 // Clean-up function (fires after converters)
8582 jqXHR.always(function() {
8583 // Restore preexisting value
8584 window[ callbackName ] = overwritten;
8585
8586 // Save back as free
8587 if ( s[ callbackName ] ) {
8588 // make sure that re-using the options doesn't screw things around
8589 s.jsonpCallback = originalSettings.jsonpCallback;
8590
8591 // save the callback name for future use
8592 oldCallbacks.push( callbackName );
8593 }
8594
8595 // Call if it was a function and we have a response
8596 if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8597 overwritten( responseContainer[ 0 ] );
8598 }
8599
8600 responseContainer = overwritten = undefined;
8601 });
8602
8603 // Delegate to script
8604 return "script";
8605 }
8606});
8607var xhrCallbacks, xhrSupported,
8608 xhrId = 0,
8609 // #5280: Internet Explorer will keep connections alive if we don't abort on unload
8610 xhrOnUnloadAbort = window.ActiveXObject && function() {
8611 // Abort all pending requests
8612 var key;
8613 for ( key in xhrCallbacks ) {
8614 xhrCallbacks[ key ]( undefined, true );
8615 }
8616 };
8617
8618// Functions to create xhrs
8619function createStandardXHR() {
8620 try {
8621 return new window.XMLHttpRequest();
8622 } catch( e ) {}
8623}
8624
8625function createActiveXHR() {
8626 try {
8627 return new window.ActiveXObject("Microsoft.XMLHTTP");
8628 } catch( e ) {}
8629}
8630
8631// Create the request object
8632// (This is still attached to ajaxSettings for backward compatibility)
8633jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8634 /* Microsoft failed to properly
8635 * implement the XMLHttpRequest in IE7 (can't request local files),
8636 * so we use the ActiveXObject when it is available
8637 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8638 * we need a fallback.
8639 */
8640 function() {
8641 return !this.isLocal && createStandardXHR() || createActiveXHR();
8642 } :
8643 // For all other browsers, use the standard XMLHttpRequest object
8644 createStandardXHR;
8645
8646// Determine support properties
8647xhrSupported = jQuery.ajaxSettings.xhr();
8648jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8649xhrSupported = jQuery.support.ajax = !!xhrSupported;
8650
8651// Create transport if the browser can provide an xhr
8652if ( xhrSupported ) {
8653
8654 jQuery.ajaxTransport(function( s ) {
8655 // Cross domain only allowed if supported through XMLHttpRequest
8656 if ( !s.crossDomain || jQuery.support.cors ) {
8657
8658 var callback;
8659
8660 return {
8661 send: function( headers, complete ) {
8662
8663 // Get a new xhr
8664 var handle, i,
8665 xhr = s.xhr();
8666
8667 // Open the socket
8668 // Passing null username, generates a login popup on Opera (#2865)
8669 if ( s.username ) {
8670 xhr.open( s.type, s.url, s.async, s.username, s.password );
8671 } else {
8672 xhr.open( s.type, s.url, s.async );
8673 }
8674
8675 // Apply custom fields if provided
8676 if ( s.xhrFields ) {
8677 for ( i in s.xhrFields ) {
8678 xhr[ i ] = s.xhrFields[ i ];
8679 }
8680 }
8681
8682 // Override mime type if needed
8683 if ( s.mimeType && xhr.overrideMimeType ) {
8684 xhr.overrideMimeType( s.mimeType );
8685 }
8686
8687 // X-Requested-With header
8688 // For cross-domain requests, seeing as conditions for a preflight are
8689 // akin to a jigsaw puzzle, we simply never set it to be sure.
8690 // (it can always be set on a per-request basis or even using ajaxSetup)
8691 // For same-domain requests, won't change header if already provided.
8692 if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8693 headers["X-Requested-With"] = "XMLHttpRequest";
8694 }
8695
8696 // Need an extra try/catch for cross domain requests in Firefox 3
8697 try {
8698 for ( i in headers ) {
8699 xhr.setRequestHeader( i, headers[ i ] );
8700 }
8701 } catch( err ) {}
8702
8703 // Do send the request
8704 // This may raise an exception which is actually
8705 // handled in jQuery.ajax (so no try/catch here)
8706 xhr.send( ( s.hasContent && s.data ) || null );
8707
8708 // Listener
8709 callback = function( _, isAbort ) {
8710 var status, responseHeaders, statusText, responses;
8711
8712 // Firefox throws exceptions when accessing properties
8713 // of an xhr when a network error occurred
8714 // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8715 try {
8716
8717 // Was never called and is aborted or complete
8718 if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8719
8720 // Only called once
8721 callback = undefined;
8722
8723 // Do not keep as active anymore
8724 if ( handle ) {
8725 xhr.onreadystatechange = jQuery.noop;
8726 if ( xhrOnUnloadAbort ) {
8727 delete xhrCallbacks[ handle ];
8728 }
8729 }
8730
8731 // If it's an abort
8732 if ( isAbort ) {
8733 // Abort it manually if needed
8734 if ( xhr.readyState !== 4 ) {
8735 xhr.abort();
8736 }
8737 } else {
8738 responses = {};
8739 status = xhr.status;
8740 responseHeaders = xhr.getAllResponseHeaders();
8741
8742 // When requesting binary data, IE6-9 will throw an exception
8743 // on any attempt to access responseText (#11426)
8744 if ( typeof xhr.responseText === "string" ) {
8745 responses.text = xhr.responseText;
8746 }
8747
8748 // Firefox throws an exception when accessing
8749 // statusText for faulty cross-domain requests
8750 try {
8751 statusText = xhr.statusText;
8752 } catch( e ) {
8753 // We normalize with Webkit giving an empty statusText
8754 statusText = "";
8755 }
8756
8757 // Filter status for non standard behaviors
8758
8759 // If the request is local and we have data: assume a success
8760 // (success with no data won't get notified, that's the best we
8761 // can do given current implementations)
8762 if ( !status && s.isLocal && !s.crossDomain ) {
8763 status = responses.text ? 200 : 404;
8764 // IE - #1450: sometimes returns 1223 when it should be 204
8765 } else if ( status === 1223 ) {
8766 status = 204;
8767 }
8768 }
8769 }
8770 } catch( firefoxAccessException ) {
8771 if ( !isAbort ) {
8772 complete( -1, firefoxAccessException );
8773 }
8774 }
8775
8776 // Call complete if needed
8777 if ( responses ) {
8778 complete( status, statusText, responses, responseHeaders );
8779 }
8780 };
8781
8782 if ( !s.async ) {
8783 // if we're in sync mode we fire the callback
8784 callback();
8785 } else if ( xhr.readyState === 4 ) {
8786 // (IE6 & IE7) if it's in cache and has been
8787 // retrieved directly we need to fire the callback
8788 setTimeout( callback );
8789 } else {
8790 handle = ++xhrId;
8791 if ( xhrOnUnloadAbort ) {
8792 // Create the active xhrs callbacks list if needed
8793 // and attach the unload handler
8794 if ( !xhrCallbacks ) {
8795 xhrCallbacks = {};
8796 jQuery( window ).unload( xhrOnUnloadAbort );
8797 }
8798 // Add to list of active xhrs callbacks
8799 xhrCallbacks[ handle ] = callback;
8800 }
8801 xhr.onreadystatechange = callback;
8802 }
8803 },
8804
8805 abort: function() {
8806 if ( callback ) {
8807 callback( undefined, true );
8808 }
8809 }
8810 };
8811 }
8812 });
8813}
8814var fxNow, timerId,
8815 rfxtypes = /^(?:toggle|show|hide)$/,
8816 rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
8817 rrun = /queueHooks$/,
8818 animationPrefilters = [ defaultPrefilter ],
8819 tweeners = {
8820 "*": [function( prop, value ) {
8821 var tween = this.createTween( prop, value ),
8822 target = tween.cur(),
8823 parts = rfxnum.exec( value ),
8824 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
8825
8826 // Starting value computation is required for potential unit mismatches
8827 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
8828 rfxnum.exec( jQuery.css( tween.elem, prop ) ),
8829 scale = 1,
8830 maxIterations = 20;
8831
8832 if ( start && start[ 3 ] !== unit ) {
8833 // Trust units reported by jQuery.css
8834 unit = unit || start[ 3 ];
8835
8836 // Make sure we update the tween properties later on
8837 parts = parts || [];
8838
8839 // Iteratively approximate from a nonzero starting point
8840 start = +target || 1;
8841
8842 do {
8843 // If previous iteration zeroed out, double until we get *something*
8844 // Use a string for doubling factor so we don't accidentally see scale as unchanged below
8845 scale = scale || ".5";
8846
8847 // Adjust and apply
8848 start = start / scale;
8849 jQuery.style( tween.elem, prop, start + unit );
8850
8851 // Update scale, tolerating zero or NaN from tween.cur()
8852 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
8853 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
8854 }
8855
8856 // Update tween properties
8857 if ( parts ) {
8858 start = tween.start = +start || +target || 0;
8859 tween.unit = unit;
8860 // If a +=/-= token was provided, we're doing a relative animation
8861 tween.end = parts[ 1 ] ?
8862 start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
8863 +parts[ 2 ];
8864 }
8865
8866 return tween;
8867 }]
8868 };
8869
8870// Animations created synchronously will run synchronously
8871function createFxNow() {
8872 setTimeout(function() {
8873 fxNow = undefined;
8874 });
8875 return ( fxNow = jQuery.now() );
8876}
8877
8878function createTween( value, prop, animation ) {
8879 var tween,
8880 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
8881 index = 0,
8882 length = collection.length;
8883 for ( ; index < length; index++ ) {
8884 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
8885
8886 // we're done with this property
8887 return tween;
8888 }
8889 }
8890}
8891
8892function Animation( elem, properties, options ) {
8893 var result,
8894 stopped,
8895 index = 0,
8896 length = animationPrefilters.length,
8897 deferred = jQuery.Deferred().always( function() {
8898 // don't match elem in the :animated selector
8899 delete tick.elem;
8900 }),
8901 tick = function() {
8902 if ( stopped ) {
8903 return false;
8904 }
8905 var currentTime = fxNow || createFxNow(),
8906 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
8907 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
8908 temp = remaining / animation.duration || 0,
8909 percent = 1 - temp,
8910 index = 0,
8911 length = animation.tweens.length;
8912
8913 for ( ; index < length ; index++ ) {
8914 animation.tweens[ index ].run( percent );
8915 }
8916
8917 deferred.notifyWith( elem, [ animation, percent, remaining ]);
8918
8919 if ( percent < 1 && length ) {
8920 return remaining;
8921 } else {
8922 deferred.resolveWith( elem, [ animation ] );
8923 return false;
8924 }
8925 },
8926 animation = deferred.promise({
8927 elem: elem,
8928 props: jQuery.extend( {}, properties ),
8929 opts: jQuery.extend( true, { specialEasing: {} }, options ),
8930 originalProperties: properties,
8931 originalOptions: options,
8932 startTime: fxNow || createFxNow(),
8933 duration: options.duration,
8934 tweens: [],
8935 createTween: function( prop, end ) {
8936 var tween = jQuery.Tween( elem, animation.opts, prop, end,
8937 animation.opts.specialEasing[ prop ] || animation.opts.easing );
8938 animation.tweens.push( tween );
8939 return tween;
8940 },
8941 stop: function( gotoEnd ) {
8942 var index = 0,
8943 // if we are going to the end, we want to run all the tweens
8944 // otherwise we skip this part
8945 length = gotoEnd ? animation.tweens.length : 0;
8946 if ( stopped ) {
8947 return this;
8948 }
8949 stopped = true;
8950 for ( ; index < length ; index++ ) {
8951 animation.tweens[ index ].run( 1 );
8952 }
8953
8954 // resolve when we played the last frame
8955 // otherwise, reject
8956 if ( gotoEnd ) {
8957 deferred.resolveWith( elem, [ animation, gotoEnd ] );
8958 } else {
8959 deferred.rejectWith( elem, [ animation, gotoEnd ] );
8960 }
8961 return this;
8962 }
8963 }),
8964 props = animation.props;
8965
8966 propFilter( props, animation.opts.specialEasing );
8967
8968 for ( ; index < length ; index++ ) {
8969 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8970 if ( result ) {
8971 return result;
8972 }
8973 }
8974
8975 jQuery.map( props, createTween, animation );
8976
8977 if ( jQuery.isFunction( animation.opts.start ) ) {
8978 animation.opts.start.call( elem, animation );
8979 }
8980
8981 jQuery.fx.timer(
8982 jQuery.extend( tick, {
8983 elem: elem,
8984 anim: animation,
8985 queue: animation.opts.queue
8986 })
8987 );
8988
8989 // attach callbacks from options
8990 return animation.progress( animation.opts.progress )
8991 .done( animation.opts.done, animation.opts.complete )
8992 .fail( animation.opts.fail )
8993 .always( animation.opts.always );
8994}
8995
8996function propFilter( props, specialEasing ) {
8997 var index, name, easing, value, hooks;
8998
8999 // camelCase, specialEasing and expand cssHook pass
9000 for ( index in props ) {
9001 name = jQuery.camelCase( index );
9002 easing = specialEasing[ name ];
9003 value = props[ index ];
9004 if ( jQuery.isArray( value ) ) {
9005 easing = value[ 1 ];
9006 value = props[ index ] = value[ 0 ];
9007 }
9008
9009 if ( index !== name ) {
9010 props[ name ] = value;
9011 delete props[ index ];
9012 }
9013
9014 hooks = jQuery.cssHooks[ name ];
9015 if ( hooks && "expand" in hooks ) {
9016 value = hooks.expand( value );
9017 delete props[ name ];
9018
9019 // not quite $.extend, this wont overwrite keys already present.
9020 // also - reusing 'index' from above because we have the correct "name"
9021 for ( index in value ) {
9022 if ( !( index in props ) ) {
9023 props[ index ] = value[ index ];
9024 specialEasing[ index ] = easing;
9025 }
9026 }
9027 } else {
9028 specialEasing[ name ] = easing;
9029 }
9030 }
9031}
9032
9033jQuery.Animation = jQuery.extend( Animation, {
9034
9035 tweener: function( props, callback ) {
9036 if ( jQuery.isFunction( props ) ) {
9037 callback = props;
9038 props = [ "*" ];
9039 } else {
9040 props = props.split(" ");
9041 }
9042
9043 var prop,
9044 index = 0,
9045 length = props.length;
9046
9047 for ( ; index < length ; index++ ) {
9048 prop = props[ index ];
9049 tweeners[ prop ] = tweeners[ prop ] || [];
9050 tweeners[ prop ].unshift( callback );
9051 }
9052 },
9053
9054 prefilter: function( callback, prepend ) {
9055 if ( prepend ) {
9056 animationPrefilters.unshift( callback );
9057 } else {
9058 animationPrefilters.push( callback );
9059 }
9060 }
9061});
9062
9063function defaultPrefilter( elem, props, opts ) {
9064 /* jshint validthis: true */
9065 var prop, value, toggle, tween, hooks, oldfire,
9066 anim = this,
9067 orig = {},
9068 style = elem.style,
9069 hidden = elem.nodeType && isHidden( elem ),
9070 dataShow = jQuery._data( elem, "fxshow" );
9071
9072 // handle queue: false promises
9073 if ( !opts.queue ) {
9074 hooks = jQuery._queueHooks( elem, "fx" );
9075 if ( hooks.unqueued == null ) {
9076 hooks.unqueued = 0;
9077 oldfire = hooks.empty.fire;
9078 hooks.empty.fire = function() {
9079 if ( !hooks.unqueued ) {
9080 oldfire();
9081 }
9082 };
9083 }
9084 hooks.unqueued++;
9085
9086 anim.always(function() {
9087 // doing this makes sure that the complete handler will be called
9088 // before this completes
9089 anim.always(function() {
9090 hooks.unqueued--;
9091 if ( !jQuery.queue( elem, "fx" ).length ) {
9092 hooks.empty.fire();
9093 }
9094 });
9095 });
9096 }
9097
9098 // height/width overflow pass
9099 if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
9100 // Make sure that nothing sneaks out
9101 // Record all 3 overflow attributes because IE does not
9102 // change the overflow attribute when overflowX and
9103 // overflowY are set to the same value
9104 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
9105
9106 // Set display property to inline-block for height/width
9107 // animations on inline elements that are having width/height animated
9108 if ( jQuery.css( elem, "display" ) === "inline" &&
9109 jQuery.css( elem, "float" ) === "none" ) {
9110
9111 // inline-level elements accept inline-block;
9112 // block-level elements need to be inline with layout
9113 if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
9114 style.display = "inline-block";
9115
9116 } else {
9117 style.zoom = 1;
9118 }
9119 }
9120 }
9121
9122 if ( opts.overflow ) {
9123 style.overflow = "hidden";
9124 if ( !jQuery.support.shrinkWrapBlocks ) {
9125 anim.always(function() {
9126 style.overflow = opts.overflow[ 0 ];
9127 style.overflowX = opts.overflow[ 1 ];
9128 style.overflowY = opts.overflow[ 2 ];
9129 });
9130 }
9131 }
9132
9133
9134 // show/hide pass
9135 for ( prop in props ) {
9136 value = props[ prop ];
9137 if ( rfxtypes.exec( value ) ) {
9138 delete props[ prop ];
9139 toggle = toggle || value === "toggle";
9140 if ( value === ( hidden ? "hide" : "show" ) ) {
9141 continue;
9142 }
9143 orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
9144 }
9145 }
9146
9147 if ( !jQuery.isEmptyObject( orig ) ) {
9148 if ( dataShow ) {
9149 if ( "hidden" in dataShow ) {
9150 hidden = dataShow.hidden;
9151 }
9152 } else {
9153 dataShow = jQuery._data( elem, "fxshow", {} );
9154 }
9155
9156 // store state if its toggle - enables .stop().toggle() to "reverse"
9157 if ( toggle ) {
9158 dataShow.hidden = !hidden;
9159 }
9160 if ( hidden ) {
9161 jQuery( elem ).show();
9162 } else {
9163 anim.done(function() {
9164 jQuery( elem ).hide();
9165 });
9166 }
9167 anim.done(function() {
9168 var prop;
9169 jQuery._removeData( elem, "fxshow" );
9170 for ( prop in orig ) {
9171 jQuery.style( elem, prop, orig[ prop ] );
9172 }
9173 });
9174 for ( prop in orig ) {
9175 tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
9176
9177 if ( !( prop in dataShow ) ) {
9178 dataShow[ prop ] = tween.start;
9179 if ( hidden ) {
9180 tween.end = tween.start;
9181 tween.start = prop === "width" || prop === "height" ? 1 : 0;
9182 }
9183 }
9184 }
9185 }
9186}
9187
9188function Tween( elem, options, prop, end, easing ) {
9189 return new Tween.prototype.init( elem, options, prop, end, easing );
9190}
9191jQuery.Tween = Tween;
9192
9193Tween.prototype = {
9194 constructor: Tween,
9195 init: function( elem, options, prop, end, easing, unit ) {
9196 this.elem = elem;
9197 this.prop = prop;
9198 this.easing = easing || "swing";
9199 this.options = options;
9200 this.start = this.now = this.cur();
9201 this.end = end;
9202 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
9203 },
9204 cur: function() {
9205 var hooks = Tween.propHooks[ this.prop ];
9206
9207 return hooks && hooks.get ?
9208 hooks.get( this ) :
9209 Tween.propHooks._default.get( this );
9210 },
9211 run: function( percent ) {
9212 var eased,
9213 hooks = Tween.propHooks[ this.prop ];
9214
9215 if ( this.options.duration ) {
9216 this.pos = eased = jQuery.easing[ this.easing ](
9217 percent, this.options.duration * percent, 0, 1, this.options.duration
9218 );
9219 } else {
9220 this.pos = eased = percent;
9221 }
9222 this.now = ( this.end - this.start ) * eased + this.start;
9223
9224 if ( this.options.step ) {
9225 this.options.step.call( this.elem, this.now, this );
9226 }
9227
9228 if ( hooks && hooks.set ) {
9229 hooks.set( this );
9230 } else {
9231 Tween.propHooks._default.set( this );
9232 }
9233 return this;
9234 }
9235};
9236
9237Tween.prototype.init.prototype = Tween.prototype;
9238
9239Tween.propHooks = {
9240 _default: {
9241 get: function( tween ) {
9242 var result;
9243
9244 if ( tween.elem[ tween.prop ] != null &&
9245 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
9246 return tween.elem[ tween.prop ];
9247 }
9248
9249 // passing an empty string as a 3rd parameter to .css will automatically
9250 // attempt a parseFloat and fallback to a string if the parse fails
9251 // so, simple values such as "10px" are parsed to Float.
9252 // complex values such as "rotate(1rad)" are returned as is.
9253 result = jQuery.css( tween.elem, tween.prop, "" );
9254 // Empty strings, null, undefined and "auto" are converted to 0.
9255 return !result || result === "auto" ? 0 : result;
9256 },
9257 set: function( tween ) {
9258 // use step hook for back compat - use cssHook if its there - use .style if its
9259 // available and use plain properties where available
9260 if ( jQuery.fx.step[ tween.prop ] ) {
9261 jQuery.fx.step[ tween.prop ]( tween );
9262 } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
9263 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
9264 } else {
9265 tween.elem[ tween.prop ] = tween.now;
9266 }
9267 }
9268 }
9269};
9270
9271// Support: IE <=9
9272// Panic based approach to setting things on disconnected nodes
9273
9274Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
9275 set: function( tween ) {
9276 if ( tween.elem.nodeType && tween.elem.parentNode ) {
9277 tween.elem[ tween.prop ] = tween.now;
9278 }
9279 }
9280};
9281
9282jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
9283 var cssFn = jQuery.fn[ name ];
9284 jQuery.fn[ name ] = function( speed, easing, callback ) {
9285 return speed == null || typeof speed === "boolean" ?
9286 cssFn.apply( this, arguments ) :
9287 this.animate( genFx( name, true ), speed, easing, callback );
9288 };
9289});
9290
9291jQuery.fn.extend({
9292 fadeTo: function( speed, to, easing, callback ) {
9293
9294 // show any hidden elements after setting opacity to 0
9295 return this.filter( isHidden ).css( "opacity", 0 ).show()
9296
9297 // animate to the value specified
9298 .end().animate({ opacity: to }, speed, easing, callback );
9299 },
9300 animate: function( prop, speed, easing, callback ) {
9301 var empty = jQuery.isEmptyObject( prop ),
9302 optall = jQuery.speed( speed, easing, callback ),
9303 doAnimation = function() {
9304 // Operate on a copy of prop so per-property easing won't be lost
9305 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
9306
9307 // Empty animations, or finishing resolves immediately
9308 if ( empty || jQuery._data( this, "finish" ) ) {
9309 anim.stop( true );
9310 }
9311 };
9312 doAnimation.finish = doAnimation;
9313
9314 return empty || optall.queue === false ?
9315 this.each( doAnimation ) :
9316 this.queue( optall.queue, doAnimation );
9317 },
9318 stop: function( type, clearQueue, gotoEnd ) {
9319 var stopQueue = function( hooks ) {
9320 var stop = hooks.stop;
9321 delete hooks.stop;
9322 stop( gotoEnd );
9323 };
9324
9325 if ( typeof type !== "string" ) {
9326 gotoEnd = clearQueue;
9327 clearQueue = type;
9328 type = undefined;
9329 }
9330 if ( clearQueue && type !== false ) {
9331 this.queue( type || "fx", [] );
9332 }
9333
9334 return this.each(function() {
9335 var dequeue = true,
9336 index = type != null && type + "queueHooks",
9337 timers = jQuery.timers,
9338 data = jQuery._data( this );
9339
9340 if ( index ) {
9341 if ( data[ index ] && data[ index ].stop ) {
9342 stopQueue( data[ index ] );
9343 }
9344 } else {
9345 for ( index in data ) {
9346 if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
9347 stopQueue( data[ index ] );
9348 }
9349 }
9350 }
9351
9352 for ( index = timers.length; index--; ) {
9353 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
9354 timers[ index ].anim.stop( gotoEnd );
9355 dequeue = false;
9356 timers.splice( index, 1 );
9357 }
9358 }
9359
9360 // start the next in the queue if the last step wasn't forced
9361 // timers currently will call their complete callbacks, which will dequeue
9362 // but only if they were gotoEnd
9363 if ( dequeue || !gotoEnd ) {
9364 jQuery.dequeue( this, type );
9365 }
9366 });
9367 },
9368 finish: function( type ) {
9369 if ( type !== false ) {
9370 type = type || "fx";
9371 }
9372 return this.each(function() {
9373 var index,
9374 data = jQuery._data( this ),
9375 queue = data[ type + "queue" ],
9376 hooks = data[ type + "queueHooks" ],
9377 timers = jQuery.timers,
9378 length = queue ? queue.length : 0;
9379
9380 // enable finishing flag on private data
9381 data.finish = true;
9382
9383 // empty the queue first
9384 jQuery.queue( this, type, [] );
9385
9386 if ( hooks && hooks.stop ) {
9387 hooks.stop.call( this, true );
9388 }
9389
9390 // look for any active animations, and finish them
9391 for ( index = timers.length; index--; ) {
9392 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
9393 timers[ index ].anim.stop( true );
9394 timers.splice( index, 1 );
9395 }
9396 }
9397
9398 // look for any animations in the old queue and finish them
9399 for ( index = 0; index < length; index++ ) {
9400 if ( queue[ index ] && queue[ index ].finish ) {
9401 queue[ index ].finish.call( this );
9402 }
9403 }
9404
9405 // turn off finishing flag
9406 delete data.finish;
9407 });
9408 }
9409});
9410
9411// Generate parameters to create a standard animation
9412function genFx( type, includeWidth ) {
9413 var which,
9414 attrs = { height: type },
9415 i = 0;
9416
9417 // if we include width, step value is 1 to do all cssExpand values,
9418 // if we don't include width, step value is 2 to skip over Left and Right
9419 includeWidth = includeWidth? 1 : 0;
9420 for( ; i < 4 ; i += 2 - includeWidth ) {
9421 which = cssExpand[ i ];
9422 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
9423 }
9424
9425 if ( includeWidth ) {
9426 attrs.opacity = attrs.width = type;
9427 }
9428
9429 return attrs;
9430}
9431
9432// Generate shortcuts for custom animations
9433jQuery.each({
9434 slideDown: genFx("show"),
9435 slideUp: genFx("hide"),
9436 slideToggle: genFx("toggle"),
9437 fadeIn: { opacity: "show" },
9438 fadeOut: { opacity: "hide" },
9439 fadeToggle: { opacity: "toggle" }
9440}, function( name, props ) {
9441 jQuery.fn[ name ] = function( speed, easing, callback ) {
9442 return this.animate( props, speed, easing, callback );
9443 };
9444});
9445
9446jQuery.speed = function( speed, easing, fn ) {
9447 var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9448 complete: fn || !fn && easing ||
9449 jQuery.isFunction( speed ) && speed,
9450 duration: speed,
9451 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9452 };
9453
9454 opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9455 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9456
9457 // normalize opt.queue - true/undefined/null -> "fx"
9458 if ( opt.queue == null || opt.queue === true ) {
9459 opt.queue = "fx";
9460 }
9461
9462 // Queueing
9463 opt.old = opt.complete;
9464
9465 opt.complete = function() {
9466 if ( jQuery.isFunction( opt.old ) ) {
9467 opt.old.call( this );
9468 }
9469
9470 if ( opt.queue ) {
9471 jQuery.dequeue( this, opt.queue );
9472 }
9473 };
9474
9475 return opt;
9476};
9477
9478jQuery.easing = {
9479 linear: function( p ) {
9480 return p;
9481 },
9482 swing: function( p ) {
9483 return 0.5 - Math.cos( p*Math.PI ) / 2;
9484 }
9485};
9486
9487jQuery.timers = [];
9488jQuery.fx = Tween.prototype.init;
9489jQuery.fx.tick = function() {
9490 var timer,
9491 timers = jQuery.timers,
9492 i = 0;
9493
9494 fxNow = jQuery.now();
9495
9496 for ( ; i < timers.length; i++ ) {
9497 timer = timers[ i ];
9498 // Checks the timer has not already been removed
9499 if ( !timer() && timers[ i ] === timer ) {
9500 timers.splice( i--, 1 );
9501 }
9502 }
9503
9504 if ( !timers.length ) {
9505 jQuery.fx.stop();
9506 }
9507 fxNow = undefined;
9508};
9509
9510jQuery.fx.timer = function( timer ) {
9511 if ( timer() && jQuery.timers.push( timer ) ) {
9512 jQuery.fx.start();
9513 }
9514};
9515
9516jQuery.fx.interval = 13;
9517
9518jQuery.fx.start = function() {
9519 if ( !timerId ) {
9520 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
9521 }
9522};
9523
9524jQuery.fx.stop = function() {
9525 clearInterval( timerId );
9526 timerId = null;
9527};
9528
9529jQuery.fx.speeds = {
9530 slow: 600,
9531 fast: 200,
9532 // Default speed
9533 _default: 400
9534};
9535
9536// Back Compat <1.8 extension point
9537jQuery.fx.step = {};
9538
9539if ( jQuery.expr && jQuery.expr.filters ) {
9540 jQuery.expr.filters.animated = function( elem ) {
9541 return jQuery.grep(jQuery.timers, function( fn ) {
9542 return elem === fn.elem;
9543 }).length;
9544 };
9545}
9546jQuery.fn.offset = function( options ) {
9547 if ( arguments.length ) {
9548 return options === undefined ?
9549 this :
9550 this.each(function( i ) {
9551 jQuery.offset.setOffset( this, options, i );
9552 });
9553 }
9554
9555 var docElem, win,
9556 box = { top: 0, left: 0 },
9557 elem = this[ 0 ],
9558 doc = elem && elem.ownerDocument;
9559
9560 if ( !doc ) {
9561 return;
9562 }
9563
9564 docElem = doc.documentElement;
9565
9566 // Make sure it's not a disconnected DOM node
9567 if ( !jQuery.contains( docElem, elem ) ) {
9568 return box;
9569 }
9570
9571 // If we don't have gBCR, just use 0,0 rather than error
9572 // BlackBerry 5, iOS 3 (original iPhone)
9573 if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
9574 box = elem.getBoundingClientRect();
9575 }
9576 win = getWindow( doc );
9577 return {
9578 top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
9579 left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
9580 };
9581};
9582
9583jQuery.offset = {
9584
9585 setOffset: function( elem, options, i ) {
9586 var position = jQuery.css( elem, "position" );
9587
9588 // set position first, in-case top/left are set even on static elem
9589 if ( position === "static" ) {
9590 elem.style.position = "relative";
9591 }
9592
9593 var curElem = jQuery( elem ),
9594 curOffset = curElem.offset(),
9595 curCSSTop = jQuery.css( elem, "top" ),
9596 curCSSLeft = jQuery.css( elem, "left" ),
9597 calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9598 props = {}, curPosition = {}, curTop, curLeft;
9599
9600 // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9601 if ( calculatePosition ) {
9602 curPosition = curElem.position();
9603 curTop = curPosition.top;
9604 curLeft = curPosition.left;
9605 } else {
9606 curTop = parseFloat( curCSSTop ) || 0;
9607 curLeft = parseFloat( curCSSLeft ) || 0;
9608 }
9609
9610 if ( jQuery.isFunction( options ) ) {
9611 options = options.call( elem, i, curOffset );
9612 }
9613
9614 if ( options.top != null ) {
9615 props.top = ( options.top - curOffset.top ) + curTop;
9616 }
9617 if ( options.left != null ) {
9618 props.left = ( options.left - curOffset.left ) + curLeft;
9619 }
9620
9621 if ( "using" in options ) {
9622 options.using.call( elem, props );
9623 } else {
9624 curElem.css( props );
9625 }
9626 }
9627};
9628
9629
9630jQuery.fn.extend({
9631
9632 position: function() {
9633 if ( !this[ 0 ] ) {
9634 return;
9635 }
9636
9637 var offsetParent, offset,
9638 parentOffset = { top: 0, left: 0 },
9639 elem = this[ 0 ];
9640
9641 // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
9642 if ( jQuery.css( elem, "position" ) === "fixed" ) {
9643 // we assume that getBoundingClientRect is available when computed position is fixed
9644 offset = elem.getBoundingClientRect();
9645 } else {
9646 // Get *real* offsetParent
9647 offsetParent = this.offsetParent();
9648
9649 // Get correct offsets
9650 offset = this.offset();
9651 if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9652 parentOffset = offsetParent.offset();
9653 }
9654
9655 // Add offsetParent borders
9656 parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9657 parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9658 }
9659
9660 // Subtract parent offsets and element margins
9661 // note: when an element has margin: auto the offsetLeft and marginLeft
9662 // are the same in Safari causing offset.left to incorrectly be 0
9663 return {
9664 top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9665 left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
9666 };
9667 },
9668
9669 offsetParent: function() {
9670 return this.map(function() {
9671 var offsetParent = this.offsetParent || docElem;
9672 while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
9673 offsetParent = offsetParent.offsetParent;
9674 }
9675 return offsetParent || docElem;
9676 });
9677 }
9678});
9679
9680
9681// Create scrollLeft and scrollTop methods
9682jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
9683 var top = /Y/.test( prop );
9684
9685 jQuery.fn[ method ] = function( val ) {
9686 return jQuery.access( this, function( elem, method, val ) {
9687 var win = getWindow( elem );
9688
9689 if ( val === undefined ) {
9690 return win ? (prop in win) ? win[ prop ] :
9691 win.document.documentElement[ method ] :
9692 elem[ method ];
9693 }
9694
9695 if ( win ) {
9696 win.scrollTo(
9697 !top ? val : jQuery( win ).scrollLeft(),
9698 top ? val : jQuery( win ).scrollTop()
9699 );
9700
9701 } else {
9702 elem[ method ] = val;
9703 }
9704 }, method, val, arguments.length, null );
9705 };
9706});
9707
9708function getWindow( elem ) {
9709 return jQuery.isWindow( elem ) ?
9710 elem :
9711 elem.nodeType === 9 ?
9712 elem.defaultView || elem.parentWindow :
9713 false;
9714}
9715// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9716jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9717 jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9718 // margin is only for outerHeight, outerWidth
9719 jQuery.fn[ funcName ] = function( margin, value ) {
9720 var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9721 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9722
9723 return jQuery.access( this, function( elem, type, value ) {
9724 var doc;
9725
9726 if ( jQuery.isWindow( elem ) ) {
9727 // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9728 // isn't a whole lot we can do. See pull request at this URL for discussion:
9729 // https://github.com/jquery/jquery/pull/764
9730 return elem.document.documentElement[ "client" + name ];
9731 }
9732
9733 // Get document width or height
9734 if ( elem.nodeType === 9 ) {
9735 doc = elem.documentElement;
9736
9737 // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
9738 // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
9739 return Math.max(
9740 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9741 elem.body[ "offset" + name ], doc[ "offset" + name ],
9742 doc[ "client" + name ]
9743 );
9744 }
9745
9746 return value === undefined ?
9747 // Get width or height on the element, requesting but not forcing parseFloat
9748 jQuery.css( elem, type, extra ) :
9749
9750 // Set width or height on the element
9751 jQuery.style( elem, type, value, extra );
9752 }, type, chainable ? margin : undefined, chainable, null );
9753 };
9754 });
9755});
9756// Limit scope pollution from any deprecated API
9757// (function() {
9758
9759// The number of elements contained in the matched element set
9760jQuery.fn.size = function() {
9761 return this.length;
9762};
9763
9764jQuery.fn.andSelf = jQuery.fn.addBack;
9765
9766// })();
9767if ( typeof module === "object" && module && typeof module.exports === "object" ) {
9768 // Expose jQuery as module.exports in loaders that implement the Node
9769 // module pattern (including browserify). Do not create the global, since
9770 // the user will be storing it themselves locally, and globals are frowned
9771 // upon in the Node module world.
9772 module.exports = jQuery;
9773} else {
9774 // Otherwise expose jQuery to the global object as usual
9775 window.jQuery = window.$ = jQuery;
9776
9777 // Register as a named AMD module, since jQuery can be concatenated with other
9778 // files that may use define, but not via a proper concatenation script that
9779 // understands anonymous AMD modules. A named AMD is safest and most robust
9780 // way to register. Lowercase jquery is used because AMD module names are
9781 // derived from file names, and jQuery is normally delivered in a lowercase
9782 // file name. Do this after creating the global so that if an AMD module wants
9783 // to call noConflict to hide this version of jQuery, it will work.
9784 if ( typeof define === "function" && define.amd ) {
9785 define( "jquery", [], function () { return jQuery; } );
9786 }
9787}
9788
9789})( window );
diff --git a/static/vendor/jquery.mobile-1.3.2.css b/static/vendor/jquery.mobile-1.3.2.css
deleted file mode 100644
index 96a75f0..0000000
--- a/static/vendor/jquery.mobile-1.3.2.css
+++ /dev/null
@@ -1,3370 +0,0 @@
1/*!
2* jQuery Mobile 1.3.2
3* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
4* http://jquerymobile.com
5*
6* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
7* Released under the MIT license.
8* http://jquery.org/license
9*
10*/
11
12
13/* Swatches */
14/* A
15-----------------------------------------------------------------------------------------------------------*/
16.ui-bar-a {
17 border: 1px solid #333 /*{a-bar-border}*/;
18 background: #111 /*{a-bar-background-color}*/;
19 color: #fff /*{a-bar-color}*/;
20 font-weight: bold;
21 text-shadow: 0 /*{a-bar-shadow-x}*/ -1px /*{a-bar-shadow-y}*/ 0 /*{a-bar-shadow-radius}*/ #000 /*{a-bar-shadow-color}*/;
22 background-image: -webkit-gradient(linear, left top, left bottom, from( #3c3c3c /*{a-bar-background-start}*/), to( #111 /*{a-bar-background-end}*/)); /* Saf4+, Chrome */
23 background-image: -webkit-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
24 background-image: -moz-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* FF3.6 */
25 background-image: -ms-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* IE10 */
26 background-image: -o-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Opera 11.10+ */
27 background-image: linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/);
28}
29.ui-bar-a,
30.ui-bar-a input,
31.ui-bar-a select,
32.ui-bar-a textarea,
33.ui-bar-a button {
34 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
35}
36.ui-bar-a .ui-link-inherit {
37 color: #fff /*{a-bar-color}*/;
38}
39.ui-bar-a a.ui-link {
40 color: #7cc4e7 /*{a-bar-link-color}*/;
41 font-weight: bold;
42}
43.ui-bar-a a.ui-link:visited {
44 color: #2489ce /*{a-bar-link-visited}*/;
45}
46.ui-bar-a a.ui-link:hover {
47 color: #2489ce /*{a-bar-link-hover}*/;
48}
49.ui-bar-a a.ui-link:active {
50 color: #2489ce /*{a-bar-link-active}*/;
51}
52.ui-body-a,
53.ui-overlay-a {
54 border: 1px solid #444 /*{a-body-border}*/;
55 background: #222 /*{a-body-background-color}*/;
56 color: #fff /*{a-body-color}*/;
57 text-shadow: 0 /*{a-body-shadow-x}*/ 1px /*{a-body-shadow-y}*/ 0 /*{a-body-shadow-radius}*/ #111 /*{a-body-shadow-color}*/;
58 font-weight: normal;
59 background-image: -webkit-gradient(linear, left top, left bottom, from( #444 /*{a-body-background-start}*/), to( #222 /*{a-body-background-end}*/)); /* Saf4+, Chrome */
60 background-image: -webkit-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
61 background-image: -moz-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* FF3.6 */
62 background-image: -ms-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* IE10 */
63 background-image: -o-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Opera 11.10+ */
64 background-image: linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/);
65}
66.ui-overlay-a {
67 background-image: none;
68 border-width: 0;
69}
70.ui-body-a,
71.ui-body-a input,
72.ui-body-a select,
73.ui-body-a textarea,
74.ui-body-a button {
75 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
76}
77.ui-body-a .ui-link-inherit {
78 color: #fff /*{a-body-color}*/;
79}
80.ui-body-a .ui-link {
81 color: #2489ce /*{a-body-link-color}*/;
82 font-weight: bold;
83}
84.ui-body-a .ui-link:visited {
85 color: #2489ce /*{a-body-link-visited}*/;
86}
87.ui-body-a .ui-link:hover {
88 color: #2489ce /*{a-body-link-hover}*/;
89}
90.ui-body-a .ui-link:active {
91 color: #2489ce /*{a-body-link-active}*/;
92}
93.ui-btn-up-a {
94 border: 1px solid #111 /*{a-bup-border}*/;
95 background: #333 /*{a-bup-background-color}*/;
96 font-weight: bold;
97 color: #fff /*{a-bup-color}*/;
98 text-shadow: 0 /*{a-bup-shadow-x}*/ 1px /*{a-bup-shadow-y}*/ 0 /*{a-bup-shadow-radius}*/ #111 /*{a-bup-shadow-color}*/;
99 background-image: -webkit-gradient(linear, left top, left bottom, from( #444 /*{a-bup-background-start}*/), to( #2d2d2d /*{a-bup-background-end}*/)); /* Saf4+, Chrome */
100 background-image: -webkit-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
101 background-image: -moz-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* FF3.6 */
102 background-image: -ms-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* IE10 */
103 background-image: -o-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Opera 11.10+ */
104 background-image: linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/);
105}
106.ui-btn-up-a:visited,
107.ui-btn-up-a a.ui-link-inherit {
108 color: #fff /*{a-bup-color}*/;
109}
110.ui-btn-hover-a {
111 border: 1px solid #000 /*{a-bhover-border}*/;
112 background: #444 /*{a-bhover-background-color}*/;
113 font-weight: bold;
114 color: #fff /*{a-bhover-color}*/;
115 text-shadow: 0 /*{a-bhover-shadow-x}*/ 1px /*{a-bhover-shadow-y}*/ 0 /*{a-bhover-shadow-radius}*/ #111 /*{a-bhover-shadow-color}*/;
116 background-image: -webkit-gradient(linear, left top, left bottom, from( #555 /*{a-bhover-background-start}*/), to( #383838 /*{a-bhover-background-end}*/)); /* Saf4+, Chrome */
117 background-image: -webkit-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
118 background-image: -moz-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* FF3.6 */
119 background-image: -ms-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* IE10 */
120 background-image: -o-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Opera 11.10+ */
121 background-image: linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/);
122}
123.ui-btn-hover-a:visited,
124.ui-btn-hover-a:hover,
125.ui-btn-hover-a a.ui-link-inherit {
126 color: #fff /*{a-bhover-color}*/;
127}
128.ui-btn-down-a {
129 border: 1px solid #000 /*{a-bdown-border}*/;
130 background: #222 /*{a-bdown-background-color}*/;
131 font-weight: bold;
132 color: #fff /*{a-bdown-color}*/;
133 text-shadow: 0 /*{a-bdown-shadow-x}*/ 1px /*{a-bdown-shadow-y}*/ 0 /*{a-bdown-shadow-radius}*/ #111 /*{a-bdown-shadow-color}*/;
134 background-image: -webkit-gradient(linear, left top, left bottom, from( #202020 /*{a-bdown-background-start}*/), to( #2c2c2c /*{a-bdown-background-end}*/)); /* Saf4+, Chrome */
135 background-image: -webkit-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
136 background-image: -moz-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* FF3.6 */
137 background-image: -ms-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* IE10 */
138 background-image: -o-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Opera 11.10+ */
139 background-image: linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/);
140}
141.ui-btn-down-a:visited,
142.ui-btn-down-a:hover,
143.ui-btn-down-a a.ui-link-inherit {
144 color: #fff /*{a-bdown-color}*/;
145}
146.ui-btn-up-a,
147.ui-btn-hover-a,
148.ui-btn-down-a {
149 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
150 text-decoration: none;
151}
152/* B
153-----------------------------------------------------------------------------------------------------------*/
154.ui-bar-b {
155 border: 1px solid #456f9a /*{b-bar-border}*/;
156 background: #5e87b0 /*{b-bar-background-color}*/;
157 color: #fff /*{b-bar-color}*/;
158 font-weight: bold;
159 text-shadow: 0 /*{b-bar-shadow-x}*/ 1px /*{b-bar-shadow-y}*/ 0 /*{b-bar-shadow-radius}*/ #3e6790 /*{b-bar-shadow-color}*/;
160 background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bar-background-start}*/), to( #497bae /*{b-bar-background-end}*/)); /* Saf4+, Chrome */
161 background-image: -webkit-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
162 background-image: -moz-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* FF3.6 */
163 background-image: -ms-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* IE10 */
164 background-image: -o-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Opera 11.10+ */
165 background-image: linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/);
166}
167.ui-bar-b,
168.ui-bar-b input,
169.ui-bar-b select,
170.ui-bar-b textarea,
171.ui-bar-b button {
172 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
173}
174.ui-bar-b .ui-link-inherit {
175 color: #fff /*{b-bar-color}*/;
176}
177.ui-bar-b a.ui-link {
178 color: #ddf0f8 /*{b-bar-link-color}*/;
179 font-weight: bold;
180}
181.ui-bar-b a.ui-link:visited {
182 color: #ddf0f8 /*{b-bar-link-visited}*/;
183}
184.ui-bar-b a.ui-link:hover {
185 color: #ddf0f8 /*{b-bar-link-hover}*/;
186}
187.ui-bar-b a.ui-link:active {
188 color: #ddf0f8 /*{b-bar-link-active}*/;
189}
190.ui-body-b,
191.ui-overlay-b {
192 border: 1px solid #999 /*{b-body-border}*/;
193 background: #f3f3f3 /*{b-body-background-color}*/;
194 color: #222 /*{b-body-color}*/;
195 text-shadow: 0 /*{b-body-shadow-x}*/ 1px /*{b-body-shadow-y}*/ 0 /*{b-body-shadow-radius}*/ #fff /*{b-body-shadow-color}*/;
196 font-weight: normal;
197 background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{b-body-background-start}*/), to( #ccc /*{b-body-background-end}*/)); /* Saf4+, Chrome */
198 background-image: -webkit-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
199 background-image: -moz-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* FF3.6 */
200 background-image: -ms-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* IE10 */
201 background-image: -o-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Opera 11.10+ */
202 background-image: linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/);
203}
204.ui-overlay-b {
205 background-image: none;
206 border-width: 0;
207}
208.ui-body-b,
209.ui-body-b input,
210.ui-body-b select,
211.ui-body-b textarea,
212.ui-body-b button {
213 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
214}
215.ui-body-b .ui-link-inherit {
216 color: #333 /*{b-body-color}*/;
217}
218.ui-body-b .ui-link {
219 color: #2489ce /*{b-body-link-color}*/;
220 font-weight: bold;
221}
222.ui-body-b .ui-link:visited {
223 color: #2489ce /*{b-body-link-visited}*/;
224}
225.ui-body-b .ui-link:hover {
226 color: #2489ce /*{b-body-link-hover}*/;
227}
228.ui-body-b .ui-link:active {
229 color: #2489ce /*{b-body-link-active}*/;
230}
231.ui-btn-up-b {
232 border: 1px solid #044062 /*{b-bup-border}*/;
233 background: #396b9e /*{b-bup-background-color}*/;
234 font-weight: bold;
235 color: #fff /*{b-bup-color}*/;
236 text-shadow: 0 /*{b-bup-shadow-x}*/ 1px /*{b-bup-shadow-y}*/ 0 /*{b-bup-shadow-radius}*/ #194b7e /*{b-bup-shadow-color}*/;
237 background-image: -webkit-gradient(linear, left top, left bottom, from( #5f9cc5 /*{b-bup-background-start}*/), to( #396b9e /*{b-bup-background-end}*/)); /* Saf4+, Chrome */
238 background-image: -webkit-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
239 background-image: -moz-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* FF3.6 */
240 background-image: -ms-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* IE10 */
241 background-image: -o-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Opera 11.10+ */
242 background-image: linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/);
243}
244.ui-btn-up-b:visited,
245.ui-btn-up-b a.ui-link-inherit {
246 color: #fff /*{b-bup-color}*/;
247}
248.ui-btn-hover-b {
249 border: 1px solid #00415e /*{b-bhover-border}*/;
250 background: #4b88b6 /*{b-bhover-background-color}*/;
251 font-weight: bold;
252 color: #fff /*{b-bhover-color}*/;
253 text-shadow: 0 /*{b-bhover-shadow-x}*/ 1px /*{b-bhover-shadow-y}*/ 0 /*{b-bhover-shadow-radius}*/ #194b7e /*{b-bhover-shadow-color}*/;
254 background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bhover-background-start}*/), to( #4272a4 /*{b-bhover-background-end}*/)); /* Saf4+, Chrome */
255 background-image: -webkit-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
256 background-image: -moz-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* FF3.6 */
257 background-image: -ms-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* IE10 */
258 background-image: -o-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Opera 11.10+ */
259 background-image: linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/);
260}
261.ui-btn-hover-b:visited,
262.ui-btn-hover-b:hover,
263.ui-btn-hover-b a.ui-link-inherit {
264 color: #fff /*{b-bhover-color}*/;
265}
266.ui-btn-down-b {
267 border: 1px solid #225377 /*{b-bdown-border}*/;
268 background: #4e89c5 /*{b-bdown-background-color}*/;
269 font-weight: bold;
270 color: #fff /*{b-bdown-color}*/;
271 text-shadow: 0 /*{b-bdown-shadow-x}*/ 1px /*{b-bdown-shadow-y}*/ 0 /*{b-bdown-shadow-radius}*/ #194b7e /*{b-bdown-shadow-color}*/;
272 background-image: -webkit-gradient(linear, left top, left bottom, from( #295b8e /*{b-bdown-background-start}*/), to( #3e79b5 /*{b-bdown-background-end}*/)); /* Saf4+, Chrome */
273 background-image: -webkit-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
274 background-image: -moz-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* FF3.6 */
275 background-image: -ms-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* IE10 */
276 background-image: -o-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Opera 11.10+ */
277 background-image: linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/);
278}
279.ui-btn-down-b:visited,
280.ui-btn-down-b:hover,
281.ui-btn-down-b a.ui-link-inherit {
282 color: #fff /*{b-bdown-color}*/;
283}
284.ui-btn-up-b,
285.ui-btn-hover-b,
286.ui-btn-down-b {
287 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
288 text-decoration: none;
289}
290/* C
291-----------------------------------------------------------------------------------------------------------*/
292.ui-bar-c {
293 border: 1px solid #b3b3b3 /*{c-bar-border}*/;
294 background: #eee /*{c-bar-background-color}*/;
295 color: #3e3e3e /*{c-bar-color}*/;
296 font-weight: bold;
297 text-shadow: 0 /*{c-bar-shadow-x}*/ 1px /*{c-bar-shadow-y}*/ 0 /*{c-bar-shadow-radius}*/ #fff /*{c-bar-shadow-color}*/;
298 background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{c-bar-background-start}*/), to( #ddd /*{c-bar-background-end}*/)); /* Saf4+, Chrome */
299 background-image: -webkit-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
300 background-image: -moz-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* FF3.6 */
301 background-image: -ms-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* IE10 */
302 background-image: -o-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Opera 11.10+ */
303 background-image: linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/);
304}
305.ui-bar-c .ui-link-inherit {
306 color: #3e3e3e /*{c-bar-color}*/;
307}
308.ui-bar-c a.ui-link {
309 color: #7cc4e7 /*{c-bar-link-color}*/;
310 font-weight: bold;
311}
312.ui-bar-c a.ui-link:visited {
313 color: #2489ce /*{c-bar-link-visited}*/;
314}
315.ui-bar-c a.ui-link:hover {
316 color: #2489ce /*{c-bar-link-hover}*/;
317}
318.ui-bar-c a.ui-link:active {
319 color: #2489ce /*{c-bar-link-active}*/;
320}
321.ui-bar-c,
322.ui-bar-c input,
323.ui-bar-c select,
324.ui-bar-c textarea,
325.ui-bar-c button {
326 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
327}
328.ui-body-c,
329.ui-overlay-c {
330 border: 1px solid #aaa /*{c-body-border}*/;
331 color: #333 /*{c-body-color}*/;
332 text-shadow: 0 /*{c-body-shadow-x}*/ 1px /*{c-body-shadow-y}*/ 0 /*{c-body-shadow-radius}*/ #fff /*{c-body-shadow-color}*/;
333 background: #f9f9f9 /*{c-body-background-color}*/;
334 background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{c-body-background-start}*/), to( #eee /*{c-body-background-end}*/)); /* Saf4+, Chrome */
335 background-image: -webkit-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
336 background-image: -moz-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* FF3.6 */
337 background-image: -ms-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* IE10 */
338 background-image: -o-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* Opera 11.10+ */
339 background-image: linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/);
340}
341.ui-overlay-c {
342 background-image: none;
343 border-width: 0;
344}
345.ui-body-c,
346.ui-body-c input,
347.ui-body-c select,
348.ui-body-c textarea,
349.ui-body-c button {
350 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
351}
352.ui-body-c .ui-link-inherit {
353 color: #333 /*{c-body-color}*/;
354}
355.ui-body-c .ui-link {
356 color: #2489ce /*{c-body-link-color}*/;
357 font-weight: bold;
358}
359.ui-body-c .ui-link:visited {
360 color: #2489ce /*{c-body-link-visited}*/;
361}
362.ui-body-c .ui-link:hover {
363 color: #2489ce /*{c-body-link-hover}*/;
364}
365.ui-body-c .ui-link:active {
366 color: #2489ce /*{c-body-link-active}*/;
367}
368.ui-btn-up-c {
369 border: 1px solid #ccc /*{c-bup-border}*/;
370 background: #eee /*{c-bup-background-color}*/;
371 font-weight: bold;
372 color: #222 /*{c-bup-color}*/;
373 text-shadow: 0 /*{c-bup-shadow-x}*/ 1px /*{c-bup-shadow-y}*/ 0 /*{c-bup-shadow-radius}*/ #fff /*{c-bup-shadow-color}*/;
374 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff /*{c-bup-background-start}*/), to( #f1f1f1 /*{c-bup-background-end}*/)); /* Saf4+, Chrome */
375 background-image: -webkit-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
376 background-image: -moz-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* FF3.6 */
377 background-image: -ms-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* IE10 */
378 background-image: -o-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Opera 11.10+ */
379 background-image: linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/);
380}
381.ui-btn-up-c:visited,
382.ui-btn-up-c a.ui-link-inherit {
383 color: #2f3e46 /*{c-bup-color}*/;
384}
385.ui-btn-hover-c {
386 border: 1px solid #bbb /*{c-bhover-border}*/;
387 background: #dfdfdf /*{c-bhover-background-color}*/;
388 font-weight: bold;
389 color: #222 /*{c-bhover-color}*/;
390 text-shadow: 0 /*{c-bhover-shadow-x}*/ 1px /*{c-bhover-shadow-y}*/ 0 /*{c-bhover-shadow-radius}*/ #fff /*{c-bhover-shadow-color}*/;
391 background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{c-bhover-background-start}*/), to( #e0e0e0 /*{c-bhover-background-end}*/)); /* Saf4+, Chrome */
392 background-image: -webkit-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
393 background-image: -moz-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* FF3.6 */
394 background-image: -ms-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* IE10 */
395 background-image: -o-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Opera 11.10+ */
396 background-image: linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/);
397}
398.ui-btn-hover-c:visited,
399.ui-btn-hover-c:hover,
400.ui-btn-hover-c a.ui-link-inherit {
401 color: #2f3e46 /*{c-bhover-color}*/;
402}
403.ui-btn-down-c {
404 border: 1px solid #bbb /*{c-bdown-border}*/;
405 background: #d6d6d6 /*{c-bdown-background-color}*/;
406 font-weight: bold;
407 color: #222 /*{c-bdown-color}*/;
408 text-shadow: 0 /*{c-bdown-shadow-x}*/ 1px /*{c-bdown-shadow-y}*/ 0 /*{c-bdown-shadow-radius}*/ #fff /*{c-bdown-shadow-color}*/;
409 background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{c-bdown-background-start}*/), to( #dfdfdf /*{c-bdown-background-end}*/)); /* Saf4+, Chrome */
410 background-image: -webkit-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
411 background-image: -moz-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* FF3.6 */
412 background-image: -ms-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* IE10 */
413 background-image: -o-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Opera 11.10+ */
414 background-image: linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/);
415}
416.ui-btn-down-c:visited,
417.ui-btn-down-c:hover,
418.ui-btn-down-c a.ui-link-inherit {
419 color: #2f3e46 /*{c-bdown-color}*/;
420}
421.ui-btn-up-c,
422.ui-btn-hover-c,
423.ui-btn-down-c {
424 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
425 text-decoration: none;
426}
427/* D
428-----------------------------------------------------------------------------------------------------------*/
429.ui-bar-d {
430 border: 1px solid #bbb /*{d-bar-border}*/;
431 background: #bbb /*{d-bar-background-color}*/;
432 color: #333 /*{d-bar-color}*/;
433 font-weight: bold;
434 text-shadow: 0 /*{d-bar-shadow-x}*/ 1px /*{d-bar-shadow-y}*/ 0 /*{d-bar-shadow-radius}*/ #eee /*{d-bar-shadow-color}*/;
435 background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{d-bar-background-start}*/), to( #bbb /*{d-bar-background-end}*/)); /* Saf4+, Chrome */
436 background-image: -webkit-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
437 background-image: -moz-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* FF3.6 */
438 background-image: -ms-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* IE10 */
439 background-image: -o-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Opera 11.10+ */
440 background-image: linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/);
441}
442.ui-bar-d,
443.ui-bar-d input,
444.ui-bar-d select,
445.ui-bar-d textarea,
446.ui-bar-d button {
447 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
448}
449.ui-bar-d .ui-link-inherit {
450 color: #333 /*{d-bar-color}*/;
451}
452.ui-bar-d a.ui-link {
453 color: #2489ce /*{d-bar-link-color}*/;
454 font-weight: bold;
455}
456.ui-bar-d a.ui-link:visited {
457 color: #2489ce /*{d-bar-link-visited}*/;
458}
459.ui-bar-d a.ui-link:hover {
460 color: #2489ce /*{d-bar-link-hover}*/;
461}
462.ui-bar-d a.ui-link:active {
463 color: #2489ce /*{d-bar-link-active}*/;
464}
465.ui-body-d,
466.ui-overlay-d {
467 border: 1px solid #bbb /*{d-body-border}*/;
468 color: #333 /*{d-body-color}*/;
469 text-shadow: 0 /*{d-body-shadow-x}*/ 1px /*{d-body-shadow-y}*/ 0 /*{d-body-shadow-radius}*/ #fff /*{d-body-shadow-color}*/;
470 background: #fff /*{d-body-background-color}*/;
471 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff /*{d-body-background-start}*/), to( #fff /*{d-body-background-end}*/)); /* Saf4+, Chrome */
472 background-image: -webkit-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
473 background-image: -moz-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* FF3.6 */
474 background-image: -ms-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* IE10 */
475 background-image: -o-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Opera 11.10+ */
476 background-image: linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/);
477}
478.ui-overlay-d {
479 background-image: none;
480 border-width: 0;
481}
482.ui-body-d,
483.ui-body-d input,
484.ui-body-d select,
485.ui-body-d textarea,
486.ui-body-d button {
487 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
488}
489.ui-body-d .ui-link-inherit {
490 color: #333 /*{d-body-color}*/;
491}
492.ui-body-d .ui-link {
493 color: #2489ce /*{d-body-link-color}*/;
494 font-weight: bold;
495}
496.ui-body-d .ui-link:visited {
497 color: #2489ce /*{d-body-link-visited}*/;
498}
499.ui-body-d .ui-link:hover {
500 color: #2489ce /*{d-body-link-hover}*/;
501}
502.ui-body-d .ui-link:active {
503 color: #2489ce /*{d-body-link-active}*/;
504}
505.ui-btn-up-d {
506 border: 1px solid #bbb /*{d-bup-border}*/;
507 background: #fff /*{d-bup-background-color}*/;
508 font-weight: bold;
509 color: #333 /*{d-bup-color}*/;
510 text-shadow: 0 /*{d-bup-shadow-x}*/ 1px /*{d-bup-shadow-y}*/ 0 /*{d-bup-shadow-radius}*/ #fff /*{d-bup-shadow-color}*/;
511 background-image: -webkit-gradient(linear, left top, left bottom, from( #fafafa /*{d-bup-background-start}*/), to( #f6f6f6 /*{d-bup-background-end}*/)); /* Saf4+, Chrome */
512 background-image: -webkit-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
513 background-image: -moz-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* FF3.6 */
514 background-image: -ms-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* IE10 */
515 background-image: -o-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Opera 11.10+ */
516 background-image: linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/);
517}
518.ui-btn-up-d:visited,
519.ui-btn-up-d a.ui-link-inherit {
520 color: #333 /*{d-bup-color}*/;
521}
522.ui-btn-hover-d {
523 border: 1px solid #aaa /*{d-bhover-border}*/;
524 background: #eee /*{d-bhover-background-color}*/;
525 font-weight: bold;
526 color: #333 /*{d-bhover-color}*/;
527 cursor: pointer;
528 text-shadow: 0 /*{d-bhover-shadow-x}*/ 1px /*{d-bhover-shadow-y}*/ 0 /*{d-bhover-shadow-radius}*/ #fff /*{d-bhover-shadow-color}*/;
529 background-image: -webkit-gradient(linear, left top, left bottom, from( #eee /*{d-bhover-background-start}*/), to( #fff /*{d-bhover-background-end}*/)); /* Saf4+, Chrome */
530 background-image: -webkit-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
531 background-image: -moz-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* FF3.6 */
532 background-image: -ms-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* IE10 */
533 background-image: -o-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Opera 11.10+ */
534 background-image: linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/);
535}
536.ui-btn-hover-d:visited,
537.ui-btn-hover-d:hover,
538.ui-btn-hover-d a.ui-link-inherit {
539 color: #333 /*{d-bhover-color}*/;
540}
541.ui-btn-down-d {
542 border: 1px solid #aaa /*{d-bdown-border}*/;
543 background: #eee /*{d-bdown-background-color}*/;
544 font-weight: bold;
545 color: #333 /*{d-bdown-color}*/;
546 text-shadow: 0 /*{d-bdown-shadow-x}*/ 1px /*{d-bdown-shadow-y}*/ 0 /*{d-bdown-shadow-radius}*/ #fff /*{d-bdown-shadow-color}*/;
547 background-image: -webkit-gradient(linear, left top, left bottom, from( #e5e5e5 /*{d-bdown-background-start}*/), to( #f2f2f2 /*{d-bdown-background-end}*/)); /* Saf4+, Chrome */
548 background-image: -webkit-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
549 background-image: -moz-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* FF3.6 */
550 background-image: -ms-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* IE10 */
551 background-image: -o-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Opera 11.10+ */
552 background-image: linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/);
553}
554.ui-btn-down-d:visited,
555.ui-btn-down-d:hover,
556.ui-btn-down-d a.ui-link-inherit {
557 color: #333 /*{d-bdown-color}*/;
558}
559.ui-btn-up-d,
560.ui-btn-hover-d,
561.ui-btn-down-d {
562 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
563 text-decoration: none;
564}
565/* E
566-----------------------------------------------------------------------------------------------------------*/
567.ui-bar-e {
568 border: 1px solid #f7c942 /*{e-bar-border}*/;
569 background: #fadb4e /*{e-bar-background-color}*/;
570 color: #333 /*{e-bar-color}*/;
571 font-weight: bold;
572 text-shadow: 0 /*{e-bar-shadow-x}*/ 1px /*{e-bar-shadow-y}*/ 0 /*{e-bar-shadow-radius}*/ #fff /*{e-bar-shadow-color}*/;
573 background-image: -webkit-gradient(linear, left top, left bottom, from( #fceda7 /*{e-bar-background-start}*/), to( #fbef7e /*{e-bar-background-end}*/)); /* Saf4+, Chrome */
574 background-image: -webkit-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
575 background-image: -moz-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* FF3.6 */
576 background-image: -ms-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* IE10 */
577 background-image: -o-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Opera 11.10+ */
578 background-image: linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/);
579}
580.ui-bar-e,
581.ui-bar-e input,
582.ui-bar-e select,
583.ui-bar-e textarea,
584.ui-bar-e button {
585 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
586}
587.ui-bar-e .ui-link-inherit {
588 color: #333 /*{e-bar-color}*/;
589}
590.ui-bar-e a.ui-link {
591 color: #2489ce /*{e-bar-link-color}*/;
592 font-weight: bold;
593}
594.ui-bar-e a.ui-link:visited {
595 color: #2489ce /*{e-bar-link-visited}*/;
596}
597.ui-bar-e a.ui-link:hover {
598 color: #2489ce /*{e-bar-link-hover}*/;
599}
600.ui-bar-e a.ui-link:active {
601 color: #2489ce /*{e-bar-link-active}*/;
602}
603.ui-body-e,
604.ui-overlay-e {
605 border: 1px solid #f7c942 /*{e-body-border}*/;
606 color: #222 /*{e-body-color}*/;
607 text-shadow: 0 /*{e-body-shadow-x}*/ 1px /*{e-body-shadow-y}*/ 0 /*{e-body-shadow-radius}*/ #fff /*{e-body-shadow-color}*/;
608 background: #fff9df /*{e-body-background-color}*/;
609 background-image: -webkit-gradient(linear, left top, left bottom, from( #fffadf /*{e-body-background-start}*/), to( #fff3a5 /*{e-body-background-end}*/)); /* Saf4+, Chrome */
610 background-image: -webkit-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
611 background-image: -moz-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* FF3.6 */
612 background-image: -ms-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* IE10 */
613 background-image: -o-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Opera 11.10+ */
614 background-image: linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/);
615}
616.ui-overlay-e {
617 background-image: none;
618 border-width: 0;
619}
620.ui-body-e,
621.ui-body-e input,
622.ui-body-e select,
623.ui-body-e textarea,
624.ui-body-e button {
625 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
626}
627.ui-body-e .ui-link-inherit {
628 color: #222 /*{e-body-color}*/;
629}
630.ui-body-e .ui-link {
631 color: #2489ce /*{e-body-link-color}*/;
632 font-weight: bold;
633}
634.ui-body-e .ui-link:visited {
635 color: #2489ce /*{e-body-link-visited}*/;
636}
637.ui-body-e .ui-link:hover {
638 color: #2489ce /*{e-body-link-hover}*/;
639}
640.ui-body-e .ui-link:active {
641 color: #2489ce /*{e-body-link-active}*/;
642}
643.ui-btn-up-e {
644 border: 1px solid #f4c63f /*{e-bup-border}*/;
645 background: #fadb4e /*{e-bup-background-color}*/;
646 font-weight: bold;
647 color: #222 /*{e-bup-color}*/;
648 text-shadow: 0 /*{e-bup-shadow-x}*/ 1px /*{e-bup-shadow-y}*/ 0 /*{e-bup-shadow-radius}*/ #fff /*{e-bup-shadow-color}*/;
649 background-image: -webkit-gradient(linear, left top, left bottom, from( #ffefaa /*{e-bup-background-start}*/), to( #ffe155 /*{e-bup-background-end}*/)); /* Saf4+, Chrome */
650 background-image: -webkit-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
651 background-image: -moz-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* FF3.6 */
652 background-image: -ms-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* IE10 */
653 background-image: -o-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Opera 11.10+ */
654 background-image: linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/);
655}
656.ui-btn-up-e:visited,
657.ui-btn-up-e a.ui-link-inherit {
658 color: #222 /*{e-bup-color}*/;
659}
660.ui-btn-hover-e {
661 border: 1px solid #f2c43d /*{e-bhover-border}*/;
662 background: #fbe26f /*{e-bhover-background-color}*/;
663 font-weight: bold;
664 color: #111 /*{e-bhover-color}*/;
665 text-shadow: 0 /*{e-bhover-shadow-x}*/ 1px /*{e-bhover-shadow-y}*/ 0 /*{e-bhover-shadow-radius}*/ #fff /*{e-bhover-shadow-color}*/;
666 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff5ba /*{e-bhover-background-start}*/), to( #fbdd52 /*{e-bhover-background-end}*/)); /* Saf4+, Chrome */
667 background-image: -webkit-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
668 background-image: -moz-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* FF3.6 */
669 background-image: -ms-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* IE10 */
670 background-image: -o-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Opera 11.10+ */
671 background-image: linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/);
672}
673.ui-btn-hover-e:visited,
674.ui-btn-hover-e:hover,
675.ui-btn-hover-e a.ui-link-inherit {
676 color: #333 /*{e-bhover-color}*/;
677}
678.ui-btn-down-e {
679 border: 1px solid #f2c43d /*{e-bdown-border}*/;
680 background: #fceda7 /*{e-bdown-background-color}*/;
681 font-weight: bold;
682 color: #111 /*{e-bdown-color}*/;
683 text-shadow: 0 /*{e-bdown-shadow-x}*/ 1px /*{e-bdown-shadow-y}*/ 0 /*{e-bdown-shadow-radius}*/ #fff /*{e-bdown-shadow-color}*/;
684 background-image: -webkit-gradient(linear, left top, left bottom, from( #f8d94c /*{e-bdown-background-start}*/), to( #fadb4e /*{e-bdown-background-end}*/)); /* Saf4+, Chrome */
685 background-image: -webkit-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
686 background-image: -moz-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* FF3.6 */
687 background-image: -ms-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* IE10 */
688 background-image: -o-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Opera 11.10+ */
689 background-image: linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/);
690}
691.ui-btn-down-e:visited,
692.ui-btn-down-e:hover,
693.ui-btn-down-e a.ui-link-inherit {
694 color: #333 /*{e-bdown-color}*/;
695}
696.ui-btn-up-e,
697.ui-btn-hover-e,
698.ui-btn-down-e {
699 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
700 text-decoration: none;
701}
702/* Structure */
703/* links within "buttons"
704-----------------------------------------------------------------------------------------------------------*/
705a.ui-link-inherit {
706 text-decoration: none !important;
707}
708/* Active class used as the "on" state across all themes
709-----------------------------------------------------------------------------------------------------------*/
710.ui-btn-active {
711 border: 1px solid #2373a5 /*{global-active-border}*/;
712 background: #5393c5 /*{global-active-background-color}*/;
713 font-weight: bold;
714 color: #fff /*{global-active-color}*/;
715 cursor: pointer;
716 text-shadow: 0 /*{global-active-shadow-x}*/ 1px /*{global-active-shadow-y}*/ 0 /*{global-active-shadow-radius}*/ #3373a5 /*{global-active-shadow-color}*/;
717 text-decoration: none;
718 background-image: -webkit-gradient(linear, left top, left bottom, from( #5393c5 /*{global-active-background-start}*/), to( #6facd5 /*{global-active-background-end}*/)); /* Saf4+, Chrome */
719 background-image: -webkit-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Chrome 10+, Saf5.1+ */
720 background-image: -moz-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* FF3.6 */
721 background-image: -ms-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* IE10 */
722 background-image: -o-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Opera 11.10+ */
723 background-image: linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/);
724 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
725}
726.ui-btn-active:visited,
727.ui-btn-active:hover,
728.ui-btn-active a.ui-link-inherit {
729 color: #fff /*{global-active-color}*/;
730}
731/* button inner top highlight
732-----------------------------------------------------------------------------------------------------------*/
733.ui-btn-inner {
734 border-top: 1px solid #fff;
735 border-color: rgba(255,255,255,.3);
736}
737/* corner rounding classes
738-----------------------------------------------------------------------------------------------------------*/
739.ui-corner-all {
740 -webkit-border-radius: .6em /*{global-radii-blocks}*/;
741 border-radius: .6em /*{global-radii-blocks}*/;
742}
743/* Form field separator
744-----------------------------------------------------------------------------------------------------------*/
745.ui-br {
746 border-color: rgb(130,130,130);
747 border-color: rgba(130,130,130,.3);
748 border-style: solid;
749}
750/* Interaction cues
751-----------------------------------------------------------------------------------------------------------*/
752.ui-disabled {
753 filter: Alpha(Opacity=30);
754 opacity: .3;
755 zoom: 1;
756}
757.ui-disabled,
758.ui-disabled a {
759 cursor: default !important;
760 pointer-events: none;
761}
762/* Icons
763-----------------------------------------------------------------------------------------------------------*/
764.ui-icon,
765.ui-icon-searchfield:after {
766 background: #666 /*{global-icon-color}*/;
767 background: rgba(0,0,0,.4) /*{global-icon-disc}*/;
768 background-image: url(images/icons-18-white.png) /*{global-icon-set}*/;
769 background-repeat: no-repeat;
770 -webkit-border-radius: 9px;
771 border-radius: 9px;
772}
773/* Alt icon color
774-----------------------------------------------------------------------------------------------------------*/
775.ui-icon-alt .ui-icon,
776.ui-icon-alt .ui-icon-searchfield:after {
777 background-color: #fff;
778 background-color: rgba(255,255,255,.3);
779 background-image: url(images/icons-18-black.png);
780 background-repeat: no-repeat;
781}
782/* No disc
783-----------------------------------------------------------------------------------------------------------*/
784.ui-icon-nodisc .ui-icon,
785.ui-icon-nodisc .ui-icon-searchfield:after,
786.ui-icon-nodisc .ui-icon-alt .ui-icon,
787.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after {
788 background-color: transparent;
789}
790/* Icon sprite
791-----------------------------------------------------------------------------------------------------------*/
792/* plus minus */
793.ui-icon-plus {
794 background-position: -1px -1px;
795}
796.ui-icon-minus {
797 background-position: -37px -1px;
798}
799/* delete/close */
800.ui-icon-delete {
801 background-position: -73px -1px;
802}
803/* arrows */
804.ui-icon-arrow-r {
805 background-position: -108px -1px;
806}
807.ui-icon-arrow-l {
808 background-position: -144px -1px;
809}
810.ui-icon-arrow-u {
811 background-position: -180px -1px;
812}
813.ui-icon-arrow-d {
814 background-position: -216px -1px;
815}
816/* misc */
817.ui-icon-check {
818 background-position: -252px -1px;
819}
820.ui-icon-gear {
821 background-position: -288px -1px;
822}
823.ui-icon-refresh {
824 background-position: -323px -1px;
825}
826.ui-icon-forward {
827 background-position: -360px -1px;
828}
829.ui-icon-back {
830 background-position: -396px -1px;
831}
832.ui-icon-grid {
833 background-position: -432px -1px;
834}
835.ui-icon-star {
836 background-position: -467px -1px;
837}
838.ui-icon-alert {
839 background-position: -503px -1px;
840}
841.ui-icon-info {
842 background-position: -539px -1px;
843}
844.ui-icon-home {
845 background-position: -575px -1px;
846}
847/* search */
848.ui-icon-search,
849.ui-icon-searchfield:after {
850 background-position: -611px -1px;
851}
852/* checkbox radio */
853.ui-icon-checkbox-on {
854 background-position: -647px -1px;
855}
856.ui-icon-checkbox-off {
857 background-position: -683px -1px;
858}
859.ui-icon-radio-on {
860 background-position: -718px -1px;
861}
862.ui-icon-radio-off {
863 background-position: -754px -1px;
864}
865/* menu edit */
866.ui-icon-bars {
867 background-position: -788px -1px;
868}
869.ui-icon-edit {
870 background-position: -824px -1px;
871}
872/* HD/"retina" sprite
873-----------------------------------------------------------------------------------------------------------*/
874@media only screen and (-webkit-min-device-pixel-ratio: 1.3),
875 only screen and (min--moz-device-pixel-ratio: 1.3),
876 only screen and (min-resolution: 200dpi) {
877
878 .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
879 .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
880 .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
881 .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-bars, .ui-icon-edit,
882 .ui-icon-search, .ui-icon-searchfield:after,
883 .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
884 background-image: url(images/icons-36-white.png);
885 -moz-background-size: 864px 18px;
886 -o-background-size: 864px 18px;
887 -webkit-background-size: 864px 18px;
888 background-size: 864px 18px;
889 }
890 .ui-icon-alt .ui-icon {
891 background-image: url(images/icons-36-black.png);
892 }
893 .ui-icon-plus {
894 background-position: 0 50%;
895 }
896 .ui-icon-minus {
897 background-position: -36px 50%;
898 }
899 .ui-icon-delete {
900 background-position: -72px 50%;
901 }
902 .ui-icon-arrow-r {
903 background-position: -108px 50%;
904 }
905 .ui-icon-arrow-l {
906 background-position: -144px 50%;
907 }
908 .ui-icon-arrow-u {
909 background-position: -179px 50%;
910 }
911 .ui-icon-arrow-d {
912 background-position: -215px 50%;
913 }
914 .ui-icon-check {
915 background-position: -252px 50%;
916 }
917 .ui-icon-gear {
918 background-position: -287px 50%;
919 }
920 .ui-icon-refresh {
921 background-position: -323px 50%;
922 }
923 .ui-icon-forward {
924 background-position: -360px 50%;
925 }
926 .ui-icon-back {
927 background-position: -395px 50%;
928 }
929 .ui-icon-grid {
930 background-position: -431px 50%;
931 }
932 .ui-icon-star {
933 background-position: -467px 50%;
934 }
935 .ui-icon-alert {
936 background-position: -503px 50%;
937 }
938 .ui-icon-info {
939 background-position: -538px 50%;
940 }
941 .ui-icon-home {
942 background-position: -575px 50%;
943 }
944 .ui-icon-search,
945 .ui-icon-searchfield:after {
946 background-position: -611px 50%;
947 }
948 .ui-icon-checkbox-on {
949 background-position: -647px 50%;
950 }
951 .ui-icon-checkbox-off {
952 background-position: -683px 50%;
953 }
954 .ui-icon-radio-on {
955 background-position: -718px 50%;
956 }
957 .ui-icon-radio-off {
958 background-position: -754px 50%;
959 }
960 .ui-icon-bars {
961 background-position: -788px 50%;
962
963 }.ui-icon-edit {
964 background-position: -824px 50%;
965 }
966}
967/* checks,radios */
968.ui-checkbox .ui-icon,
969.ui-selectmenu-list .ui-icon {
970 -webkit-border-radius: 3px;
971 border-radius: 3px;
972}
973.ui-icon-checkbox-off,
974.ui-icon-radio-off {
975 background-color: transparent;
976}
977.ui-checkbox-on .ui-icon,
978.ui-radio-on .ui-icon {
979 background-color: #4596ce /*{global-active-background-color}*/; /* NOTE: this hex should match the active state color. It's repeated here for cascade */
980}
981/* loading icon */
982.ui-icon-loading {
983 background: url(images/ajax-loader.gif);
984 background-size: 46px 46px;
985}
986/* Button corner class
987-----------------------------------------------------------------------------------------------------------*/
988.ui-btn-corner-all {
989 -webkit-border-radius: 1em /*{global-radii-buttons}*/;
990 border-radius: 1em /*{global-radii-buttons}*/;
991}
992/* radius clip workaround for cleaning up corner trapping */
993.ui-corner-all,
994.ui-btn-corner-all {
995 -webkit-background-clip: padding;
996 background-clip: padding-box;
997}
998/* Overlay / modal
999-----------------------------------------------------------------------------------------------------------*/
1000.ui-overlay {
1001 background: #666;
1002 filter: Alpha(Opacity=50);
1003 opacity: .5;
1004 position: absolute;
1005 width: 100%;
1006 height: 100%;
1007}
1008.ui-overlay-shadow {
1009 -moz-box-shadow: 0 0 12px rgba(0,0,0,.6);
1010 -webkit-box-shadow: 0 0 12px rgba(0,0,0,.6);
1011 box-shadow: 0 0 12px rgba(0,0,0,.6);
1012}
1013.ui-shadow {
1014 -moz-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/;
1015 -webkit-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/;
1016 box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/
1017}
1018.ui-bar-a .ui-shadow,
1019.ui-bar-b .ui-shadow ,
1020.ui-bar-c .ui-shadow {
1021 -moz-box-shadow: 0 1px 0 rgba(255,255,255,.3);
1022 -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.3);
1023 box-shadow: 0 1px 0 rgba(255,255,255,.3);
1024}
1025.ui-shadow-inset {
1026 -moz-box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1027 -webkit-box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1028 box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1029}
1030.ui-icon-shadow {
1031 -moz-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1032 -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1033 box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1034}
1035/* Focus state - set here for specificity (note: these classes are added by JavaScript)
1036-----------------------------------------------------------------------------------------------------------*/
1037.ui-btn:focus, .ui-link-inherit:focus {
1038 outline: 0;
1039}
1040.ui-btn.ui-focus {
1041 z-index: 1;
1042}
1043.ui-focus,
1044.ui-btn:focus {
1045 -moz-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1046 -webkit-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1047 box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1048}
1049.ui-input-text.ui-focus,
1050.ui-input-search.ui-focus {
1051 -moz-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1052 -webkit-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1053 box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1054}
1055/* unset box shadow in browsers that don't do it right
1056-----------------------------------------------------------------------------------------------------------*/
1057.ui-mobile-nosupport-boxshadow * {
1058 -moz-box-shadow: none !important;
1059 -webkit-box-shadow: none !important;
1060 box-shadow: none !important;
1061}
1062/* ...and bring back focus */
1063.ui-mobile-nosupport-boxshadow .ui-focus,
1064.ui-mobile-nosupport-boxshadow .ui-btn:focus,
1065.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus {
1066 outline-width: 1px;
1067 outline-style: auto;
1068}
1069/* some unsets - more probably needed */
1070.ui-mobile, .ui-mobile body { height: 99.9%; }
1071.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }
1072.ui-mobile a img, .ui-mobile fieldset { border-width: 0; }
1073.ui-mobile fieldset { min-width: 0; }
1074/* responsive page widths */
1075.ui-mobile-viewport { margin: 0; overflow-x: visible; -webkit-text-size-adjust: 100%; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
1076/* Issue #2066 */
1077body.ui-mobile-viewport,
1078div.ui-mobile-viewport { overflow-x: hidden; }
1079/* "page" containers - full-screen views, one should always be in view post-pageload */
1080.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; }
1081.ui-mobile .ui-page-active { display: block; overflow: visible; }
1082/* on ios4, setting focus on the page element causes flashing during transitions when there is an outline, so we turn off outlines */
1083.ui-page { outline: none; }
1084/*orientations from js are available */
1085@media screen and (orientation: portrait){
1086.ui-mobile .ui-page { min-height: 420px; }
1087}
1088@media screen and (orientation: landscape){
1089.ui-mobile .ui-page { min-height: 300px; }
1090}
1091/* loading screen */
1092.ui-loading .ui-loader { display: block; }
1093.ui-loader { display: none; z-index: 9999999; position: fixed; top: 50%; left: 50%; border:0; }
1094.ui-loader-default { background: none; filter: Alpha(Opacity=18); opacity: .18; width: 46px; height: 46px; margin-left: -23px; margin-top: -23px; }
1095.ui-loader-verbose { width: 200px; filter: Alpha(Opacity=88); opacity: .88; box-shadow: 0 1px 1px -1px #fff; height: auto; margin-left: -110px; margin-top: -43px; padding: 10px; }
1096.ui-loader-default h1 { font-size: 0; width: 0; height: 0; overflow: hidden; }
1097.ui-loader-verbose h1 { font-size: 16px; margin: 0; text-align: center; }
1098.ui-loader .ui-icon { background-color: #000; display: block; margin: 0; width: 44px; height: 44px; padding: 1px; -webkit-border-radius: 36px; border-radius: 36px; }
1099.ui-loader-verbose .ui-icon { margin: 0 auto 10px; filter: Alpha(Opacity=75); opacity: .75; }
1100.ui-loader-textonly { padding: 15px; margin-left: -115px; }
1101.ui-loader-textonly .ui-icon { display: none; }
1102.ui-loader-fakefix { position: absolute; }
1103/*fouc*/
1104.ui-mobile-rendering > * { visibility: hidden; }
1105/*headers, content panels*/
1106.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }
1107.ui-bar { font-size: 16px; margin: 0; }
1108.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; }
1109.ui-header, .ui-footer { position: relative; zoom: 1; }
1110.ui-mobile .ui-header, .ui-mobile .ui-footer { border-left-width: 0; border-right-width: 0; }
1111.ui-header .ui-btn-left,
1112.ui-header .ui-btn-right,
1113.ui-footer .ui-btn-left,
1114.ui-footer .ui-btn-right,
1115.ui-header-fixed.ui-fixed-hidden .ui-btn-left,
1116.ui-header-fixed.ui-fixed-hidden .ui-btn-right { position: absolute; top: 3px; }
1117.ui-header-fixed .ui-btn-left,
1118.ui-header-fixed .ui-btn-right { top: 4px;}
1119.ui-header .ui-btn-left,
1120.ui-footer .ui-btn-left { left: 5px; }
1121.ui-header .ui-btn-right,
1122.ui-footer .ui-btn-right { right: 5px; }
1123.ui-footer > .ui-btn-icon-notext,
1124.ui-header > .ui-btn-icon-notext,
1125.ui-header-fixed.ui-fixed-hidden > .ui-btn-icon-notext { top: 6px; }
1126.ui-header-fixed > .ui-btn-icon-notext { top: 7px;}
1127.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; }
1128.ui-footer .ui-title { margin: .6em 15px .8em; }
1129/* content area*/
1130.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }
1131/* corner styling for dialogs and popups */
1132.ui-corner-all > .ui-header:first-child,
1133.ui-corner-all > .ui-content:first-child,
1134.ui-corner-all > .ui-footer:first-child {
1135 -webkit-border-top-left-radius: inherit;
1136 border-top-left-radius: inherit;
1137 -webkit-border-top-right-radius: inherit;
1138 border-top-right-radius: inherit;
1139}
1140.ui-corner-all > .ui-header:last-child,
1141.ui-corner-all > .ui-content:last-child,
1142.ui-corner-all > .ui-footer:last-child {
1143 -webkit-border-bottom-left-radius: inherit;
1144 border-bottom-left-radius: inherit;
1145 -webkit-border-bottom-right-radius: inherit;
1146 border-bottom-right-radius: inherit;
1147}
1148/* icons sizing */
1149.ui-icon { width: 18px; height: 18px; }
1150/* non-js content hiding */
1151.ui-nojs { position: absolute; left: -9999px; }
1152/* accessible content hiding */
1153.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,
1154.ui-hidden-accessible { position: absolute !important; left: -9999px; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
1155/* Transitions originally inspired by those from jQtouch, nice work, folks */
1156.ui-mobile-viewport-transitioning,
1157.ui-mobile-viewport-transitioning .ui-page {
1158 width: 100%;
1159 height: 100%;
1160 overflow: hidden;
1161 -webkit-box-sizing: border-box;
1162 -moz-box-sizing: border-box;
1163 box-sizing: border-box;
1164}
1165.ui-page-pre-in {
1166 opacity: 0;
1167}
1168.in {
1169 -webkit-animation-timing-function: ease-out;
1170 -webkit-animation-duration: 350ms;
1171 -moz-animation-timing-function: ease-out;
1172 -moz-animation-duration: 350ms;
1173 animation-timing-function: ease-out;
1174 animation-duration: 350ms;
1175}
1176.out {
1177 -webkit-animation-timing-function: ease-in;
1178 -webkit-animation-duration: 225ms;
1179 -moz-animation-timing-function: ease-in;
1180 -moz-animation-duration: 225ms;
1181 animation-timing-function: ease-in;
1182 animation-duration: 225ms;
1183}
1184@-webkit-keyframes fadein {
1185 from { opacity: 0; }
1186 to { opacity: 1; }
1187}
1188@-moz-keyframes fadein {
1189 from { opacity: 0; }
1190 to { opacity: 1; }
1191}
1192@keyframes fadein {
1193 from { opacity: 0; }
1194 to { opacity: 1; }
1195}
1196@-webkit-keyframes fadeout {
1197 from { opacity: 1; }
1198 to { opacity: 0; }
1199}
1200@-moz-keyframes fadeout {
1201 from { opacity: 1; }
1202 to { opacity: 0; }
1203}
1204@keyframes fadeout {
1205 from { opacity: 1; }
1206 to { opacity: 0; }
1207}
1208.fade.out {
1209 opacity: 0;
1210 -webkit-animation-duration: 125ms;
1211 -webkit-animation-name: fadeout;
1212 -moz-animation-duration: 125ms;
1213 -moz-animation-name: fadeout;
1214 animation-duration: 125ms;
1215 animation-name: fadeout;
1216}
1217.fade.in {
1218 opacity: 1;
1219 -webkit-animation-duration: 225ms;
1220 -webkit-animation-name: fadein;
1221 -moz-animation-duration: 225ms;
1222 -moz-animation-name: fadein;
1223 animation-duration: 225ms;
1224 animation-name: fadein;
1225}
1226.pop {
1227 -webkit-transform-origin: 50% 50%;
1228 -moz-transform-origin: 50% 50%;
1229 transform-origin: 50% 50%;
1230}
1231.pop.in {
1232 -webkit-transform: scale(1);
1233 -webkit-animation-name: popin;
1234 -webkit-animation-duration: 350ms;
1235 -moz-transform: scale(1);
1236 -moz-animation-name: popin;
1237 -moz-animation-duration: 350ms;
1238 transform: scale(1);
1239 animation-name: popin;
1240 animation-duration: 350ms;
1241 opacity: 1;
1242}
1243.pop.out {
1244 -webkit-animation-name: fadeout;
1245 -webkit-animation-duration: 100ms;
1246 -moz-animation-name: fadeout;
1247 -moz-animation-duration: 100ms;
1248 animation-name: fadeout;
1249 animation-duration: 100ms;
1250 opacity: 0;
1251}
1252.pop.in.reverse {
1253 -webkit-animation-name: fadein;
1254 -moz-animation-name: fadein;
1255 animation-name: fadein;
1256}
1257.pop.out.reverse {
1258 -webkit-transform: scale(.8);
1259 -webkit-animation-name: popout;
1260 -moz-transform: scale(.8);
1261 -moz-animation-name: popout;
1262 transform: scale(.8);
1263 animation-name: popout;
1264}
1265@-webkit-keyframes popin {
1266 from {
1267 -webkit-transform: scale(.8);
1268 opacity: 0;
1269 }
1270 to {
1271 -webkit-transform: scale(1);
1272 opacity: 1;
1273 }
1274}
1275@-moz-keyframes popin {
1276 from {
1277 -moz-transform: scale(.8);
1278 opacity: 0;
1279 }
1280 to {
1281 -moz-transform: scale(1);
1282 opacity: 1;
1283 }
1284}
1285@keyframes popin {
1286 from {
1287 transform: scale(.8);
1288 opacity: 0;
1289 }
1290 to {
1291 transform: scale(1);
1292 opacity: 1;
1293 }
1294}
1295@-webkit-keyframes popout {
1296 from {
1297 -webkit-transform: scale(1);
1298 opacity: 1;
1299 }
1300 to {
1301 -webkit-transform: scale(.8);
1302 opacity: 0;
1303 }
1304}
1305@-moz-keyframes popout {
1306 from {
1307 -moz-transform: scale(1);
1308 opacity: 1;
1309 }
1310 to {
1311 -moz-transform: scale(.8);
1312 opacity: 0;
1313 }
1314}
1315@keyframes popout {
1316 from {
1317 transform: scale(1);
1318 opacity: 1;
1319 }
1320 to {
1321 transform: scale(.8);
1322 opacity: 0;
1323 }
1324}
1325/* keyframes for slidein from sides */
1326@-webkit-keyframes slideinfromright {
1327 from { -webkit-transform: translate3d(100%,0,0); }
1328 to { -webkit-transform: translate3d(0,0,0); }
1329}
1330@-moz-keyframes slideinfromright {
1331 from { -moz-transform: translateX(100%); }
1332 to { -moz-transform: translateX(0); }
1333}
1334@keyframes slideinfromright {
1335 from { transform: translateX(100%); }
1336 to { transform: translateX(0); }
1337}
1338@-webkit-keyframes slideinfromleft {
1339 from { -webkit-transform: translate3d(-100%,0,0); }
1340 to { -webkit-transform: translate3d(0,0,0); }
1341}
1342@-moz-keyframes slideinfromleft {
1343 from { -moz-transform: translateX(-100%); }
1344 to { -moz-transform: translateX(0); }
1345}
1346@keyframes slideinfromleft {
1347 from { transform: translateX(-100%); }
1348 to { transform: translateX(0); }
1349}
1350/* keyframes for slideout to sides */
1351@-webkit-keyframes slideouttoleft {
1352 from { -webkit-transform: translate3d(0,0,0); }
1353 to { -webkit-transform: translate3d(-100%,0,0); }
1354}
1355@-moz-keyframes slideouttoleft {
1356 from { -moz-transform: translateX(0); }
1357 to { -moz-transform: translateX(-100%); }
1358}
1359@keyframes slideouttoleft {
1360 from { transform: translateX(0); }
1361 to { transform: translateX(-100%); }
1362}
1363@-webkit-keyframes slideouttoright {
1364 from { -webkit-transform: translate3d(0,0,0); }
1365 to { -webkit-transform: translate3d(100%,0,0); }
1366}
1367@-moz-keyframes slideouttoright {
1368 from { -moz-transform: translateX(0); }
1369 to { -moz-transform: translateX(100%); }
1370}
1371@keyframes slideouttoright {
1372 from { transform: translateX(0); }
1373 to { transform: translateX(100%); }
1374}
1375.slide.out, .slide.in {
1376 -webkit-animation-timing-function: ease-out;
1377 -webkit-animation-duration: 350ms;
1378 -moz-animation-timing-function: ease-out;
1379 -moz-animation-duration: 350ms;
1380 animation-timing-function: ease-out;
1381 animation-duration: 350ms;
1382}
1383.slide.out {
1384 -webkit-transform: translate3d(-100%,0,0);
1385 -webkit-animation-name: slideouttoleft;
1386 -moz-transform: translateX(-100%);
1387 -moz-animation-name: slideouttoleft;
1388 transform: translateX(-100%);
1389 animation-name: slideouttoleft;
1390}
1391.slide.in {
1392 -webkit-transform: translate3d(0,0,0);
1393 -webkit-animation-name: slideinfromright;
1394 -moz-transform: translateX(0);
1395 -moz-animation-name: slideinfromright;
1396 transform: translateX(0);
1397 animation-name: slideinfromright;
1398}
1399.slide.out.reverse {
1400 -webkit-transform: translate3d(100%,0,0);
1401 -webkit-animation-name: slideouttoright;
1402 -moz-transform: translateX(100%);
1403 -moz-animation-name: slideouttoright;
1404 transform: translateX(100%);
1405 animation-name: slideouttoright;
1406}
1407.slide.in.reverse {
1408 -webkit-transform: translate3d(0,0,0);
1409 -webkit-animation-name: slideinfromleft;
1410 -moz-transform: translateX(0);
1411 -moz-animation-name: slideinfromleft;
1412 transform: translateX(0);
1413 animation-name: slideinfromleft;
1414}
1415.slidefade.out {
1416 -webkit-transform: translateX(-100%);
1417 -webkit-animation-name: slideouttoleft;
1418 -webkit-animation-duration: 225ms;
1419 -moz-transform: translateX(-100%);
1420 -moz-animation-name: slideouttoleft;
1421 -moz-animation-duration: 225ms;
1422 transform: translateX(-100%);
1423 animation-name: slideouttoleft;
1424 animation-duration: 225ms;
1425}
1426.slidefade.in {
1427 -webkit-transform: translateX(0);
1428 -webkit-animation-name: fadein;
1429 -webkit-animation-duration: 200ms;
1430 -moz-transform: translateX(0);
1431 -moz-animation-name: fadein;
1432 -moz-animation-duration: 200ms;
1433 transform: translateX(0);
1434 animation-name: fadein;
1435 animation-duration: 200ms;
1436}
1437.slidefade.out.reverse {
1438 -webkit-transform: translateX(100%);
1439 -webkit-animation-name: slideouttoright;
1440 -webkit-animation-duration: 200ms;
1441 -moz-transform: translateX(100%);
1442 -moz-animation-name: slideouttoright;
1443 -moz-animation-duration: 200ms;
1444 transform: translateX(100%);
1445 animation-name: slideouttoright;
1446 animation-duration: 200ms;
1447}
1448.slidefade.in.reverse {
1449 -webkit-transform: translateX(0);
1450 -webkit-animation-name: fadein;
1451 -webkit-animation-duration: 200ms;
1452 -moz-transform: translateX(0);
1453 -moz-animation-name: fadein;
1454 -moz-animation-duration: 200ms;
1455 transform: translateX(0);
1456 animation-name: fadein;
1457 animation-duration: 200ms;
1458}
1459/* slide down */
1460.slidedown.out {
1461 -webkit-animation-name: fadeout;
1462 -webkit-animation-duration: 100ms;
1463 -moz-animation-name: fadeout;
1464 -moz-animation-duration: 100ms;
1465 animation-name: fadeout;
1466 animation-duration: 100ms;
1467}
1468.slidedown.in {
1469 -webkit-transform: translateY(0);
1470 -webkit-animation-name: slideinfromtop;
1471 -webkit-animation-duration: 250ms;
1472 -moz-transform: translateY(0);
1473 -moz-animation-name: slideinfromtop;
1474 -moz-animation-duration: 250ms;
1475 transform: translateY(0);
1476 animation-name: slideinfromtop;
1477 animation-duration: 250ms;
1478}
1479.slidedown.in.reverse {
1480 -webkit-animation-name: fadein;
1481 -webkit-animation-duration: 150ms;
1482 -moz-animation-name: fadein;
1483 -moz-animation-duration: 150ms;
1484 animation-name: fadein;
1485 animation-duration: 150ms;
1486}
1487.slidedown.out.reverse {
1488 -webkit-transform: translateY(-100%);
1489 -webkit-animation-name: slideouttotop;
1490 -webkit-animation-duration: 200ms;
1491 -moz-transform: translateY(-100%);
1492 -moz-animation-name: slideouttotop;
1493 -moz-animation-duration: 200ms;
1494 transform: translateY(-100%);
1495 animation-name: slideouttotop;
1496 animation-duration: 200ms;
1497}
1498@-webkit-keyframes slideinfromtop {
1499 from { -webkit-transform: translateY(-100%); }
1500 to { -webkit-transform: translateY(0); }
1501}
1502@-moz-keyframes slideinfromtop {
1503 from { -moz-transform: translateY(-100%); }
1504 to { -moz-transform: translateY(0); }
1505}
1506@keyframes slideinfromtop {
1507 from { transform: translateY(-100%); }
1508 to { transform: translateY(0); }
1509}
1510@-webkit-keyframes slideouttotop {
1511 from { -webkit-transform: translateY(0); }
1512 to { -webkit-transform: translateY(-100%); }
1513}
1514@-moz-keyframes slideouttotop {
1515 from { -moz-transform: translateY(0); }
1516 to { -moz-transform: translateY(-100%); }
1517}
1518@keyframes slideouttotop {
1519 from { transform: translateY(0); }
1520 to { transform: translateY(-100%); }
1521}
1522/* slide up */
1523.slideup.out {
1524 -webkit-animation-name: fadeout;
1525 -webkit-animation-duration: 100ms;
1526 -moz-animation-name: fadeout;
1527 -moz-animation-duration: 100ms;
1528 animation-name: fadeout;
1529 animation-duration: 100ms;
1530}
1531.slideup.in {
1532 -webkit-transform: translateY(0);
1533 -webkit-animation-name: slideinfrombottom;
1534 -webkit-animation-duration: 250ms;
1535 -moz-transform: translateY(0);
1536 -moz-animation-name: slideinfrombottom;
1537 -moz-animation-duration: 250ms;
1538 transform: translateY(0);
1539 animation-name: slideinfrombottom;
1540 animation-duration: 250ms;
1541}
1542.slideup.in.reverse {
1543 -webkit-animation-name: fadein;
1544 -webkit-animation-duration: 150ms;
1545 -moz-animation-name: fadein;
1546 -moz-animation-duration: 150ms;
1547 animation-name: fadein;
1548 animation-duration: 150ms;
1549}
1550.slideup.out.reverse {
1551 -webkit-transform: translateY(100%);
1552 -webkit-animation-name: slideouttobottom;
1553 -webkit-animation-duration: 200ms;
1554 -moz-transform: translateY(100%);
1555 -moz-animation-name: slideouttobottom;
1556 -moz-animation-duration: 200ms;
1557 transform: translateY(100%);
1558 animation-name: slideouttobottom;
1559 animation-duration: 200ms;
1560}
1561@-webkit-keyframes slideinfrombottom {
1562 from { -webkit-transform: translateY(100%); }
1563 to { -webkit-transform: translateY(0); }
1564}
1565@-moz-keyframes slideinfrombottom {
1566 from { -moz-transform: translateY(100%); }
1567 to { -moz-transform: translateY(0); }
1568}
1569@keyframes slideinfrombottom {
1570 from { transform: translateY(100%); }
1571 to { transform: translateY(0); }
1572}
1573@-webkit-keyframes slideouttobottom {
1574 from { -webkit-transform: translateY(0); }
1575 to { -webkit-transform: translateY(100%); }
1576}
1577@-moz-keyframes slideouttobottom {
1578 from { -moz-transform: translateY(0); }
1579 to { -moz-transform: translateY(100%); }
1580}
1581@keyframes slideouttobottom {
1582 from { transform: translateY(0); }
1583 to { transform: translateY(100%); }
1584}
1585/* The properties in this rule are only necessary for the 'flip' transition.
1586 * We need specify the perspective to create a projection matrix. This will add
1587 * some depth as the element flips. The depth number represents the distance of
1588 * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
1589 * value.
1590 */
1591.viewport-flip {
1592 -webkit-perspective: 1000;
1593 -moz-perspective: 1000;
1594 perspective: 1000;
1595 position: absolute;
1596}
1597.flip {
1598 -webkit-backface-visibility: hidden;
1599 -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. */
1600 -moz-backface-visibility: hidden;
1601 -moz-transform: translateX(0);
1602 backface-visibility: hidden;
1603 transform: translateX(0);
1604}
1605.flip.out {
1606 -webkit-transform: rotateY(-90deg) scale(.9);
1607 -webkit-animation-name: flipouttoleft;
1608 -webkit-animation-duration: 175ms;
1609 -moz-transform: rotateY(-90deg) scale(.9);
1610 -moz-animation-name: flipouttoleft;
1611 -moz-animation-duration: 175ms;
1612 transform: rotateY(-90deg) scale(.9);
1613 animation-name: flipouttoleft;
1614 animation-duration: 175ms;
1615}
1616.flip.in {
1617 -webkit-animation-name: flipintoright;
1618 -webkit-animation-duration: 225ms;
1619 -moz-animation-name: flipintoright;
1620 -moz-animation-duration: 225ms;
1621 animation-name: flipintoright;
1622 animation-duration: 225ms;
1623}
1624.flip.out.reverse {
1625 -webkit-transform: rotateY(90deg) scale(.9);
1626 -webkit-animation-name: flipouttoright;
1627 -moz-transform: rotateY(90deg) scale(.9);
1628 -moz-animation-name: flipouttoright;
1629 transform: rotateY(90deg) scale(.9);
1630 animation-name: flipouttoright;
1631}
1632.flip.in.reverse {
1633 -webkit-animation-name: flipintoleft;
1634 -moz-animation-name: flipintoleft;
1635 animation-name: flipintoleft;
1636}
1637@-webkit-keyframes flipouttoleft {
1638 from { -webkit-transform: rotateY(0); }
1639 to { -webkit-transform: rotateY(-90deg) scale(.9); }
1640}
1641@-moz-keyframes flipouttoleft {
1642 from { -moz-transform: rotateY(0); }
1643 to { -moz-transform: rotateY(-90deg) scale(.9); }
1644}
1645@keyframes flipouttoleft {
1646 from { transform: rotateY(0); }
1647 to { transform: rotateY(-90deg) scale(.9); }
1648}
1649@-webkit-keyframes flipouttoright {
1650 from { -webkit-transform: rotateY(0) ; }
1651 to { -webkit-transform: rotateY(90deg) scale(.9); }
1652}
1653@-moz-keyframes flipouttoright {
1654 from { -moz-transform: rotateY(0); }
1655 to { -moz-transform: rotateY(90deg) scale(.9); }
1656}
1657@keyframes flipouttoright {
1658 from { transform: rotateY(0); }
1659 to { transform: rotateY(90deg) scale(.9); }
1660}
1661@-webkit-keyframes flipintoleft {
1662 from { -webkit-transform: rotateY(-90deg) scale(.9); }
1663 to { -webkit-transform: rotateY(0); }
1664}
1665@-moz-keyframes flipintoleft {
1666 from { -moz-transform: rotateY(-90deg) scale(.9); }
1667 to { -moz-transform: rotateY(0); }
1668}
1669@keyframes flipintoleft {
1670 from { transform: rotateY(-90deg) scale(.9); }
1671 to { transform: rotateY(0); }
1672}
1673@-webkit-keyframes flipintoright {
1674 from { -webkit-transform: rotateY(90deg) scale(.9); }
1675 to { -webkit-transform: rotateY(0); }
1676}
1677@-moz-keyframes flipintoright {
1678 from { -moz-transform: rotateY(90deg) scale(.9); }
1679 to { -moz-transform: rotateY(0); }
1680}
1681@keyframes flipintoright {
1682 from { transform: rotateY(90deg) scale(.9); }
1683 to { transform: rotateY(0); }
1684}
1685/* The properties in this rule are only necessary for the 'flip' transition.
1686 * We need specify the perspective to create a projection matrix. This will add
1687 * some depth as the element flips. The depth number represents the distance of
1688 * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
1689 * value.
1690 */
1691.viewport-turn {
1692 -webkit-perspective: 200px;
1693 -moz-perspective: 200px;
1694 -ms-perspective: 200px;
1695 perspective: 200px;
1696 position: absolute;
1697}
1698.turn {
1699 -webkit-backface-visibility: hidden;
1700 -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. */
1701 -webkit-transform-origin: 0;
1702
1703 -moz-backface-visibility: hidden;
1704 -moz-transform: translateX(0);
1705 -moz-transform-origin: 0;
1706
1707 backface-visibility :hidden;
1708 transform: translateX(0);
1709 transform-origin: 0;
1710}
1711.turn.out {
1712 -webkit-transform: rotateY(-90deg) scale(.9);
1713 -webkit-animation-name: flipouttoleft;
1714 -webkit-animation-duration: 125ms;
1715 -moz-transform: rotateY(-90deg) scale(.9);
1716 -moz-animation-name: flipouttoleft;
1717 -moz-animation-duration: 125ms;
1718 transform: rotateY(-90deg) scale(.9);
1719 animation-name: flipouttoleft;
1720 animation-duration: 125ms;
1721}
1722.turn.in {
1723 -webkit-animation-name: flipintoright;
1724 -webkit-animation-duration: 250ms;
1725 -moz-animation-name: flipintoright;
1726 -moz-animation-duration: 250ms;
1727 animation-name: flipintoright;
1728 animation-duration: 250ms;
1729
1730}
1731.turn.out.reverse {
1732 -webkit-transform: rotateY(90deg) scale(.9);
1733 -webkit-animation-name: flipouttoright;
1734 -moz-transform: rotateY(90deg) scale(.9);
1735 -moz-animation-name: flipouttoright;
1736 transform: rotateY(90deg) scale(.9);
1737 animation-name: flipouttoright;
1738}
1739.turn.in.reverse {
1740 -webkit-animation-name: flipintoleft;
1741 -moz-animation-name: flipintoleft;
1742 animation-name: flipintoleft;
1743}
1744@-webkit-keyframes flipouttoleft {
1745 from { -webkit-transform: rotateY(0); }
1746 to { -webkit-transform: rotateY(-90deg) scale(.9); }
1747}
1748@-moz-keyframes flipouttoleft {
1749 from { -moz-transform: rotateY(0); }
1750 to { -moz-transform: rotateY(-90deg) scale(.9); }
1751}
1752@keyframes flipouttoleft {
1753 from { transform: rotateY(0); }
1754 to { transform: rotateY(-90deg) scale(.9); }
1755}
1756@-webkit-keyframes flipouttoright {
1757 from { -webkit-transform: rotateY(0) ; }
1758 to { -webkit-transform: rotateY(90deg) scale(.9); }
1759}
1760@-moz-keyframes flipouttoright {
1761 from { -moz-transform: rotateY(0); }
1762 to { -moz-transform: rotateY(90deg) scale(.9); }
1763}
1764@keyframes flipouttoright {
1765 from { transform: rotateY(0); }
1766 to { transform: rotateY(90deg) scale(.9); }
1767}
1768@-webkit-keyframes flipintoleft {
1769 from { -webkit-transform: rotateY(-90deg) scale(.9); }
1770 to { -webkit-transform: rotateY(0); }
1771}
1772@-moz-keyframes flipintoleft {
1773 from { -moz-transform: rotateY(-90deg) scale(.9); }
1774 to { -moz-transform: rotateY(0); }
1775}
1776@keyframes flipintoleft {
1777 from { transform: rotateY(-90deg) scale(.9); }
1778 to { transform: rotateY(0); }
1779}
1780@-webkit-keyframes flipintoright {
1781 from { -webkit-transform: rotateY(90deg) scale(.9); }
1782 to { -webkit-transform: rotateY(0); }
1783}
1784@-moz-keyframes flipintoright {
1785 from { -moz-transform: rotateY(90deg) scale(.9); }
1786 to { -moz-transform: rotateY(0); }
1787}
1788@keyframes flipintoright {
1789 from { transform: rotateY(90deg) scale(.9); }
1790 to { transform: rotateY(0); }
1791}
1792/* flow transition */
1793.flow {
1794 -webkit-transform-origin: 50% 30%;
1795 -webkit-box-shadow: 0 0 20px rgba(0,0,0,.4);
1796 -moz-transform-origin: 50% 30%;
1797 -moz-box-shadow: 0 0 20px rgba(0,0,0,.4);
1798 transform-origin: 50% 30%;
1799 box-shadow: 0 0 20px rgba(0,0,0,.4);
1800}
1801.ui-dialog.flow {
1802 -webkit-transform-origin: none;
1803 -webkit-box-shadow: none;
1804 -moz-transform-origin: none;
1805 -moz-box-shadow: none;
1806 transform-origin: none;
1807 box-shadow: none;
1808}
1809.flow.out {
1810 -webkit-transform: translateX(-100%) scale(.7);
1811 -webkit-animation-name: flowouttoleft;
1812 -webkit-animation-timing-function: ease;
1813 -webkit-animation-duration: 350ms;
1814 -moz-transform: translateX(-100%) scale(.7);
1815 -moz-animation-name: flowouttoleft;
1816 -moz-animation-timing-function: ease;
1817 -moz-animation-duration: 350ms;
1818 transform: translateX(-100%) scale(.7);
1819 animation-name: flowouttoleft;
1820 animation-timing-function: ease;
1821 animation-duration: 350ms;
1822}
1823.flow.in {
1824 -webkit-transform: translateX(0) scale(1);
1825 -webkit-animation-name: flowinfromright;
1826 -webkit-animation-timing-function: ease;
1827 -webkit-animation-duration: 350ms;
1828 -moz-transform: translateX(0) scale(1);
1829 -moz-animation-name: flowinfromright;
1830 -moz-animation-timing-function: ease;
1831 -moz-animation-duration: 350ms;
1832 transform: translateX(0) scale(1);
1833 animation-name: flowinfromright;
1834 animation-timing-function: ease;
1835 animation-duration: 350ms;
1836}
1837.flow.out.reverse {
1838 -webkit-transform: translateX(100%);
1839 -webkit-animation-name: flowouttoright;
1840 -moz-transform: translateX(100%);
1841 -moz-animation-name: flowouttoright;
1842 transform: translateX(100%);
1843 animation-name: flowouttoright;
1844}
1845.flow.in.reverse {
1846 -webkit-animation-name: flowinfromleft;
1847 -moz-animation-name: flowinfromleft;
1848 animation-name: flowinfromleft;
1849}
1850@-webkit-keyframes flowouttoleft {
1851 0% { -webkit-transform: translateX(0) scale(1); }
1852 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
1853 100% { -webkit-transform: translateX(-100%) scale(.7); }
1854}
1855@-moz-keyframes flowouttoleft {
1856 0% { -moz-transform: translateX(0) scale(1); }
1857 60%, 70% { -moz-transform: translateX(0) scale(.7); }
1858 100% { -moz-transform: translateX(-100%) scale(.7); }
1859}
1860@keyframes flowouttoleft {
1861 0% { transform: translateX(0) scale(1); }
1862 60%, 70% { transform: translateX(0) scale(.7); }
1863 100% { transform: translateX(-100%) scale(.7); }
1864}
1865@-webkit-keyframes flowouttoright {
1866 0% { -webkit-transform: translateX(0) scale(1); }
1867 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
1868 100% { -webkit-transform: translateX(100%) scale(.7); }
1869}
1870@-moz-keyframes flowouttoright {
1871 0% { -moz-transform: translateX(0) scale(1); }
1872 60%, 70% { -moz-transform: translateX(0) scale(.7); }
1873 100% { -moz-transform: translateX(100%) scale(.7); }
1874}
1875@keyframes flowouttoright {
1876 0% { transform: translateX(0) scale(1); }
1877 60%, 70% { transform: translateX(0) scale(.7); }
1878 100% { transform: translateX(100%) scale(.7); }
1879}
1880@-webkit-keyframes flowinfromleft {
1881 0% { -webkit-transform: translateX(-100%) scale(.7); }
1882 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
1883 100% { -webkit-transform: translateX(0) scale(1); }
1884}
1885@-moz-keyframes flowinfromleft {
1886 0% { -moz-transform: translateX(-100%) scale(.7); }
1887 30%, 40% { -moz-transform: translateX(0) scale(.7); }
1888 100% { -moz-transform: translateX(0) scale(1); }
1889}
1890@keyframes flowinfromleft {
1891 0% { transform: translateX(-100%) scale(.7); }
1892 30%, 40% { transform: translateX(0) scale(.7); }
1893 100% { transform: translateX(0) scale(1); }
1894}
1895@-webkit-keyframes flowinfromright {
1896 0% { -webkit-transform: translateX(100%) scale(.7); }
1897 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
1898 100% { -webkit-transform: translateX(0) scale(1); }
1899}
1900@-moz-keyframes flowinfromright {
1901 0% { -moz-transform: translateX(100%) scale(.7); }
1902 30%, 40% { -moz-transform: translateX(0) scale(.7); }
1903 100% { -moz-transform: translateX(0) scale(1); }
1904}
1905@keyframes flowinfromright {
1906 0% { transform: translateX(100%) scale(.7); }
1907 30%, 40% { transform: translateX(0) scale(.7); }
1908 100% { transform: translateX(0) scale(1); }
1909}
1910/* content configurations. */
1911.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }
1912.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; }
1913/* grid solo: 100 - single item fallback */
1914.ui-grid-solo .ui-block-a { display: block; float: none; }
1915/* Lower percentages for older browsers (i.e. IE7) to prevent wrapping. -.5px to fix BB5 wrap issue. */
1916/* grid a: 50/50 */
1917.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 49.95%; }
1918.ui-grid-a > :nth-child(n) { width: 50%; margin-right: -.5px; }
1919.ui-grid-a .ui-block-a { clear: left; }
1920/* grid b: 33/33/33 */
1921.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.25%; }
1922.ui-grid-b > :nth-child(n) { width: 33.333%; margin-right: -.5px; }
1923.ui-grid-b .ui-block-a { clear: left; }
1924/* grid c: 25/25/25/25 */
1925.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%; }
1926.ui-grid-c > :nth-child(n) { width: 25%; margin-right: -.5px; }
1927.ui-grid-c .ui-block-a { clear: left; }
1928/* grid d: 20/20/20/20/20 */
1929.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%; }
1930.ui-grid-d > :nth-child(n) { width: 20%; }
1931.ui-grid-d .ui-block-a { clear: left; }
1932/* preset breakpoint to switch to stacked grid styles below 35em (560px) */
1933@media all and (max-width: 35em) {
1934 .ui-responsive .ui-block-a,
1935 .ui-responsive .ui-block-b,
1936 .ui-responsive .ui-block-c,
1937 .ui-responsive .ui-block-d,
1938 .ui-responsive .ui-block-e {
1939 width: 100%;
1940 float:none;
1941 }
1942}
1943/* fixed page header & footer configuration */
1944.ui-header-fixed,
1945.ui-footer-fixed {
1946 left: 0;
1947 right: 0;
1948 width: 100%;
1949 position: fixed;
1950 z-index: 1000;
1951}
1952.ui-header-fixed {
1953 top: -1px;
1954 padding-top: 1px;
1955}
1956.ui-header-fixed.ui-fixed-hidden {
1957 top: 0;
1958 padding-top: 0;
1959}
1960.ui-footer-fixed {
1961 bottom: -1px;
1962 padding-bottom: 1px;
1963}
1964.ui-footer-fixed.ui-fixed-hidden {
1965 bottom: 0;
1966 padding-bottom: 0;
1967}
1968.ui-header-fullscreen,
1969.ui-footer-fullscreen {
1970 filter: Alpha(Opacity=90);
1971 opacity: .9;
1972}
1973.ui-page-header-fixed {
1974 padding-top: 2.6875em;
1975}
1976.ui-page-footer-fixed {
1977 padding-bottom: 2.6875em;
1978}
1979.ui-page-header-fullscreen > .ui-content,
1980.ui-page-footer-fullscreen > .ui-content {
1981 padding: 0;
1982}
1983.ui-fixed-hidden {
1984 position: absolute;
1985}
1986.ui-page-header-fullscreen .ui-fixed-hidden,
1987.ui-page-footer-fullscreen .ui-fixed-hidden {
1988 left: -9999px;
1989}
1990.ui-header-fixed .ui-btn,
1991.ui-footer-fixed .ui-btn {
1992 z-index: 10;
1993}
1994/* workarounds for other widgets */
1995.ui-android-2x-fixed .ui-li-has-thumb {
1996 -webkit-transform: translate3d(0,0,0);
1997}
1998.ui-navbar { max-width: 100%; }
1999.ui-navbar.ui-mini { margin: 0; }
2000.ui-navbar ul:before, .ui-navbar ul:after { content: " "; display: table; }
2001.ui-navbar ul:after { clear: both; }
2002.ui-navbar ul { list-style:none; margin: 0; padding: 0; position: relative; display: block; border: 0; max-width: 100%; overflow: visible; zoom: 1; }
2003.ui-navbar li .ui-btn { display: block; text-align: center; margin: 0 -1px 0 0; border-right-width: 0; }
2004.ui-navbar li .ui-btn-icon-right .ui-icon { right: 6px; }
2005/* add border if not in header/footer (full width) */
2006.ui-navbar li:last-child .ui-btn,
2007.ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: 0; border-right-width: 1px; }
2008.ui-header .ui-navbar li:last-child .ui-btn,
2009.ui-footer .ui-navbar li:last-child .ui-btn,
2010.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,
2011.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: -1px; border-right-width: 0; }
2012.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn { margin-right: -1px; border-right-width: 1px; }
2013.ui-header .ui-navbar li .ui-btn,
2014.ui-footer .ui-navbar li .ui-btn { border-top-width: 0; border-bottom-width: 0; }
2015/* fixing gaps caused by subpixel problem */
2016.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,
2017.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn { margin-right: -5px; }
2018.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
2019.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
2020.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,
2021.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn { margin-right: -4px; }
2022.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
2023.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
2024.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
2025.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
2026.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,
2027.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon { right: 8px; }
2028.ui-navbar li .ui-btn .ui-btn-inner { padding-top: .7em; padding-bottom: .8em }
2029.ui-navbar li .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
2030.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
2031.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 0; padding: 0; }
2032.ui-mini { margin-top: .25em; margin-bottom: .25em; }
2033.ui-btn-left, .ui-btn-right, .ui-input-clear, .ui-btn-inline,
2034.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; margin-left: 5px; }
2035.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; }
2036.ui-btn input, .ui-btn button { z-index: 2; }
2037.ui-btn-left, .ui-btn-right, .ui-btn-inline { display: inline-block; vertical-align: middle; }
2038.ui-mobile .ui-btn-left, .ui-mobile .ui-btn-right, .ui-btn-left > .ui-btn, .ui-btn-right > .ui-btn { margin: 0; } /* .ui-mobile to increase specificity level */
2039.ui-btn-block { display: block; }
2040.ui-header > .ui-btn,
2041.ui-footer > .ui-btn { display: inline-block; margin: 0; }
2042.ui-header .ui-btn-block,
2043.ui-footer .ui-btn-block { display: block; }
2044.ui-header .ui-btn-inner,
2045.ui-footer .ui-btn-inner,
2046.ui-mini .ui-btn-inner { font-size: 12.5px; padding: .55em 11px .5em; }
2047.ui-fullsize .ui-btn-inner,
2048.ui-fullsize .ui-btn-inner { font-size: 16px; padding: .6em 20px; }
2049.ui-btn-icon-notext { width: 24px; height: 24px; }
2050.ui-btn-icon-notext .ui-btn-inner { padding: 0; height: 100%; }
2051.ui-btn-icon-notext .ui-btn-inner .ui-icon { margin: 2px 1px 2px 3px; float: left; }
2052.ui-btn-text { position: relative; z-index: 1; width: 100%; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; }
2053div.ui-btn-text { width: auto; }
2054.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -9999px; }
2055.ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
2056.ui-btn-icon-right .ui-btn-inner { padding-right: 40px; }
2057.ui-btn-icon-top .ui-btn-inner { padding-top: 40px; }
2058.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 40px; }
2059.ui-header .ui-btn-icon-left .ui-btn-inner,
2060.ui-footer .ui-btn-icon-left .ui-btn-inner,
2061.ui-mini.ui-btn-icon-left .ui-btn-inner,
2062.ui-mini .ui-btn-icon-left .ui-btn-inner { padding-left: 30px; }
2063.ui-header .ui-btn-icon-right .ui-btn-inner,
2064.ui-footer .ui-btn-icon-right .ui-btn-inner,
2065.ui-mini.ui-btn-icon-right .ui-btn-inner,
2066.ui-mini .ui-btn-icon-right .ui-btn-inner { padding-right: 30px; }
2067.ui-header .ui-btn-icon-top .ui-btn-inner,
2068.ui-footer .ui-btn-icon-top .ui-btn-inner { padding: 30px 3px .5em 3px; }
2069.ui-mini.ui-btn-icon-top .ui-btn-inner,
2070.ui-mini .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
2071.ui-header .ui-btn-icon-bottom .ui-btn-inner,
2072.ui-footer .ui-btn-icon-bottom .ui-btn-inner { padding: .55em 3px 30px 3px; }
2073.ui-mini.ui-btn-icon-bottom .ui-btn-inner,
2074.ui-mini .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
2075/* Corner styling inheritance */
2076.ui-btn-inner {
2077 -webkit-border-radius: inherit;
2078 border-radius: inherit;
2079}
2080/*btn icon positioning*/
2081.ui-btn-icon-notext .ui-icon { display: block; z-index: 0;}
2082.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; }
2083.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; }
2084.ui-btn-icon-left .ui-icon { left: 10px; }
2085.ui-btn-icon-right .ui-icon { right: 10px; }
2086.ui-btn-icon-top .ui-icon { top: 10px; }
2087.ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
2088.ui-header .ui-btn-icon-left .ui-icon,
2089.ui-footer .ui-btn-icon-left .ui-icon,
2090.ui-mini.ui-btn-icon-left .ui-icon,
2091.ui-mini .ui-btn-icon-left .ui-icon { left: 5px; }
2092.ui-header .ui-btn-icon-right .ui-icon,
2093.ui-footer .ui-btn-icon-right .ui-icon,
2094.ui-mini.ui-btn-icon-right .ui-icon,
2095.ui-mini .ui-btn-icon-right .ui-icon { right: 5px; }
2096.ui-header .ui-btn-icon-top .ui-icon,
2097.ui-footer .ui-btn-icon-top .ui-icon,
2098.ui-mini.ui-btn-icon-top .ui-icon,
2099.ui-mini .ui-btn-icon-top .ui-icon { top: 5px; }
2100.ui-header .ui-btn-icon-bottom .ui-icon,
2101.ui-footer .ui-btn-icon-bottom .ui-icon,
2102.ui-mini.ui-btn-icon-bottom .ui-icon,
2103.ui-mini .ui-btn-icon-bottom .ui-icon { bottom: 5px; }
2104/*hiding native button,inputs */
2105.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: none; cursor: pointer; background: #fff; background: rgba(255,255,255,0); filter: Alpha(Opacity=0); opacity: .1; font-size: 1px; border: none; text-indent: -9999px; }
2106/* Fixes IE/WP filter alpha opacity bugs */
2107.ui-disabled .ui-btn-hidden { display: none; }
2108.ui-disabled { z-index: 1; }
2109.ui-field-contain .ui-btn.ui-submit { margin: 0; }
2110label.ui-submit { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
2111@media all and (min-width: 28em){
2112 .ui-field-contain label.ui-submit { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
2113 .ui-field-contain .ui-btn.ui-submit { width: 78%; display: inline-block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
2114 .ui-hide-label .ui-btn.ui-submit { width: auto; display: block; }
2115}
2116.ui-collapsible-inset { margin: .5em 0; }
2117.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -15px; padding: 0; position: relative; }
2118.ui-collapsible-inset .ui-collapsible-heading { margin: 0; }
2119.ui-collapsible-heading .ui-btn { text-align: left; margin: 0; border-left-width: 0; border-right-width: 0; }
2120.ui-collapsible-inset .ui-collapsible-heading .ui-btn { border-right-width: 1px; border-left-width: 1px; }
2121.ui-collapsible-collapsed + .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn { border-top-width: 0; }
2122.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn { border-top-width: 1px; }
2123.ui-collapsible-heading .ui-btn-inner { padding-left: 12px; padding-right: 12px; }
2124.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
2125.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner { padding-right: 40px; }
2126.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,
2127.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner { text-align: center; }
2128.ui-collapsible-heading .ui-btn-icon-left.ui-mini .ui-btn-inner { padding-left: 30px; }
2129.ui-collapsible-heading .ui-btn-icon-right.ui-mini .ui-btn-inner { padding-right: 30px; }
2130.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 0 1px 2px; text-indent: -9999px; }
2131.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner { padding: 10px 0; }
2132.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon { left: 0; margin-top: -10px; }
2133.ui-collapsible-heading-status { position: absolute; top: -9999px; left: 0; }
2134.ui-collapsible-content {
2135 display: block;
2136 margin: 0 -15px;
2137 padding: 10px 15px;
2138 border-left-width: 0;
2139 border-right-width: 0;
2140 border-top: none; /* Overrides ui-body-* */
2141 background-image: none; /* Overrides ui-body-* */
2142}
2143.ui-collapsible-inset .ui-collapsible-content { margin: 0; border-right-width: 1px; border-left-width: 1px; }
2144.ui-collapsible-content-collapsed { display: none; }
2145.ui-collapsible-set > .ui-collapsible.ui-corner-all {
2146 -webkit-border-radius: 0;
2147 border-radius: 0;
2148}
2149.ui-collapsible-heading,
2150.ui-collapsible-heading > .ui-btn {
2151 -webkit-border-radius: inherit;
2152 border-radius: inherit;
2153}
2154.ui-collapsible-set .ui-collapsible.ui-first-child {
2155 -webkit-border-top-right-radius: inherit;
2156 border-top-right-radius: inherit;
2157 -webkit-border-top-left-radius: inherit;
2158 border-top-left-radius: inherit;
2159}
2160.ui-collapsible-content,
2161.ui-collapsible-set .ui-collapsible.ui-last-child {
2162 -webkit-border-bottom-right-radius: inherit;
2163 border-bottom-right-radius: inherit;
2164 -webkit-border-bottom-left-radius: inherit;
2165 border-bottom-left-radius: inherit;
2166}
2167.ui-collapsible-themed-content:not(.ui-collapsible-collapsed) > .ui-collapsible-heading {
2168 -webkit-border-bottom-right-radius: 0;
2169 border-bottom-right-radius: 0;
2170 -webkit-border-bottom-left-radius: 0;
2171 border-bottom-left-radius: 0;
2172}
2173.ui-collapsible-set { margin: .5em 0; }
2174.ui-collapsible-set .ui-collapsible { margin: -1px 0 0; }
2175.ui-collapsible-set .ui-collapsible.ui-first-child { margin-top: 0; }
2176.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0; zoom: 1; }
2177.ui-controlgroup.ui-mini, fieldset.ui-controlgroup.ui-mini { margin: .25em 0; }
2178.ui-field-contain .ui-controlgroup, .ui-field-contain fieldset.ui-controlgroup { margin: 0; }
2179.ui-bar .ui-controlgroup { margin: 0 5px; }
2180.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .4em; }
2181/* Fixes legend not wrapping on IE10 */
2182.ui-controlgroup-label legend { max-width: 100%; }
2183.ui-controlgroup-controls label.ui-select,
2184.ui-controlgroup-controls label.ui-submit { position: absolute; left: -9999px; }
2185.ui-controlgroup li { list-style: none; }
2186.ui-controlgroup .ui-btn { margin: 0; }
2187.ui-controlgroup .ui-btn-icon-notext { width: auto; height: auto; top: auto; }
2188.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { height: 20px; padding: .6em 20px .6em 20px }
2189.ui-controlgroup-horizontal .ui-btn-icon-notext .ui-btn-inner { width: 18px; }
2190.ui-controlgroup.ui-mini .ui-btn-icon-notext .ui-btn-inner,
2191.ui-header .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner,
2192.ui-footer .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { height: 16px; padding: .55em 11px .5em 11px; }
2193.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; right: 50%; margin: -9px -9px 0 0; }
2194.ui-controlgroup-horizontal .ui-btn-inner { text-align: center; }
2195.ui-controlgroup-horizontal.ui-mini .ui-btn-inner { height: 16px; line-height: 16px; }
2196.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }
2197.ui-controlgroup-horizontal .ui-controlgroup-controls:before,
2198.ui-controlgroup-horizontal .ui-controlgroup-controls:after { content: ""; display: table; }
2199.ui-controlgroup-horizontal .ui-controlgroup-controls:after { clear: both; }
2200.ui-controlgroup-horizontal .ui-controlgroup-controls { display: inline-block; vertical-align: middle; zoom: 1; }
2201.ui-controlgroup-horizontal .ui-controlgroup-controls > .ui-btn, .ui-controlgroup-horizontal .ui-controlgroup-controls li > .ui-btn,
2202.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio,
2203.ui-controlgroup-horizontal .ui-select { float: left; clear: none; margin: 0; }
2204/* On IE7 the floating selects will be displayed as block if .ui-btn-text has width 100% */
2205.ui-controlgroup-horizontal .ui-select .ui-btn-text { width: auto; }
2206.ui-controlgroup-vertical .ui-btn { border-bottom-width: 0; }
2207.ui-controlgroup-vertical .ui-btn.ui-last-child { border-bottom-width: 1px; }
2208.ui-controlgroup-horizontal .ui-btn { border-right-width: 0; }
2209.ui-controlgroup-horizontal .ui-btn.ui-last-child { border-right-width: 1px; }
2210.ui-controlgroup .ui-btn-corner-all {
2211 -webkit-border-radius: 0;
2212 border-radius: 0;
2213}
2214.ui-controlgroup .ui-controlgroup-controls,
2215.ui-controlgroup .ui-radio,
2216.ui-controlgroup .ui-checkbox,
2217.ui-controlgroup .ui-select,
2218.ui-controlgroup li {
2219 -webkit-border-radius: inherit;
2220 border-radius: inherit;
2221}
2222.ui-controlgroup-vertical .ui-btn.ui-first-child {
2223 -webkit-border-top-left-radius: inherit;
2224 border-top-left-radius: inherit;
2225 -webkit-border-top-right-radius: inherit;
2226 border-top-right-radius: inherit;
2227}
2228.ui-controlgroup-vertical .ui-btn.ui-last-child {
2229 -webkit-border-bottom-left-radius: inherit;
2230 border-bottom-left-radius: inherit;
2231 -webkit-border-bottom-right-radius: inherit;
2232 border-bottom-right-radius: inherit;
2233}
2234.ui-controlgroup-horizontal .ui-btn.ui-first-child {
2235 -webkit-border-top-left-radius: inherit;
2236 border-top-left-radius: inherit;
2237 -webkit-border-bottom-left-radius: inherit;
2238 border-bottom-left-radius: inherit;
2239}
2240.ui-controlgroup-horizontal .ui-btn.ui-last-child {
2241 -webkit-border-top-right-radius: inherit;
2242 border-top-right-radius: inherit;
2243 -webkit-border-bottom-right-radius: inherit;
2244 border-bottom-right-radius: inherit;
2245}
2246.ui-controlgroup .ui-shadow:not(.ui-focus) {
2247 -moz-box-shadow: none;
2248 -webkit-box-shadow: none;
2249 box-shadow: none;
2250}
2251@media all and (min-width: 28em){
2252 .ui-field-contain .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
2253 .ui-field-contain .ui-controlgroup-controls { width: 78%; display: inline-block; }
2254 .ui-field-contain .ui-controlgroup .ui-select { width: 100%; display: block; }
2255 .ui-field-contain .ui-controlgroup-horizontal .ui-select { width: auto; }
2256 .ui-hide-label .ui-controlgroup-controls { width: 100%; }
2257}
2258.ui-dialog {
2259 background: none !important; /* this is to ensure that dialog theming does not apply (by default at least) on the page div */
2260}
2261.ui-dialog-contain {
2262 width: 92.5%;
2263 max-width: 500px;
2264 margin: 10% auto 15px auto;
2265 padding: 0;
2266 position: relative;
2267 top: -15px;
2268}
2269.ui-dialog-contain > .ui-header,
2270.ui-dialog-contain > .ui-content,
2271.ui-dialog-contain > .ui-footer {
2272 display: block;
2273 position: relative;
2274 width: auto;
2275 margin: 0;
2276}
2277.ui-dialog-contain > .ui-header {
2278 border: none;
2279 overflow: hidden;
2280 z-index: 10;
2281 padding: 0;
2282}
2283.ui-dialog-contain > .ui-content {
2284 padding: 15px;
2285}
2286.ui-dialog-contain > .ui-footer {
2287 z-index: 10;
2288 padding: 0 15px;
2289}
2290.ui-popup-open .ui-header-fixed,
2291.ui-popup-open .ui-footer-fixed {
2292 position: absolute !important; /* See line #553 of popup.js */
2293}
2294.ui-popup-screen {
2295 background-image: url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==); /* Necessary to set some form of background to ensure element is clickable in IE6/7. While legacy IE won't understand the data-URI'd image, it ensures no additional requests occur in all other browsers with little overhead. */
2296 top: 0;
2297 left: 0;
2298 right: 0;
2299 bottom: 1px;
2300 position: absolute;
2301 filter: Alpha(Opacity=0);
2302 opacity: 0;
2303 z-index: 1099;
2304}
2305.ui-popup-screen.in {
2306 opacity: 0.5;
2307 filter: Alpha(Opacity=50);
2308}
2309.ui-popup-screen.out {
2310 opacity: 0;
2311 filter: Alpha(Opacity=0);
2312}
2313.ui-popup-container {
2314 z-index: 1100;
2315 display: inline-block;
2316 position: absolute;
2317 padding: 0;
2318 outline: 0;
2319}
2320.ui-popup {
2321 position: relative;
2322}
2323.ui-popup.ui-content,
2324.ui-popup .ui-content {
2325 overflow: visible;
2326}
2327.ui-popup > p,
2328.ui-popup > h1,
2329.ui-popup > h2,
2330.ui-popup > h3,
2331.ui-popup > h4,
2332.ui-popup > h5,
2333.ui-popup > h6 {
2334 margin: .5em 7px;
2335}
2336.ui-popup > span {
2337 display: block;
2338 margin: .5em 7px;
2339}
2340.ui-popup .ui-title {
2341 font-size: 16px;
2342 font-weight: bold;
2343 margin-top: .5em;
2344 margin-bottom: .5em;
2345}
2346.ui-popup-container .ui-content > p,
2347.ui-popup-container .ui-content > h1,
2348.ui-popup-container .ui-content > h2,
2349.ui-popup-container .ui-content > h3,
2350.ui-popup-container .ui-content > h4,
2351.ui-popup-container .ui-content > h5,
2352.ui-popup-container .ui-content > h6 {
2353 margin: .5em 0;
2354}
2355.ui-popup-container .ui-content > span {
2356 margin: 0;
2357}
2358.ui-popup-container .ui-content > p:first-child,
2359.ui-popup-container .ui-content > h1:first-child,
2360.ui-popup-container .ui-content > h2:first-child,
2361.ui-popup-container .ui-content > h3:first-child,
2362.ui-popup-container .ui-content > h4:first-child,
2363.ui-popup-container .ui-content > h5:first-child,
2364.ui-popup-container .ui-content > h6:first-child {
2365 margin-top: 0;
2366}
2367.ui-popup-container .ui-content > p:last-child,
2368.ui-popup-container .ui-content > h1:last-child,
2369.ui-popup-container .ui-content > h2:last-child,
2370.ui-popup-container .ui-content > h3:last-child,
2371.ui-popup-container .ui-content > h4:last-child,
2372.ui-popup-container .ui-content > h5:last-child,
2373.ui-popup-container .ui-content > h6:last-child {
2374 margin-bottom: 0;
2375}
2376.ui-popup > img {
2377 width: auto;
2378 height: auto;
2379 max-width: 100%;
2380 max-height: 100%;
2381 vertical-align: middle;
2382}
2383.ui-popup:not(.ui-content) > img:only-child,
2384.ui-popup:not(.ui-content) > .ui-btn-left:first-child + img:last-child,
2385.ui-popup:not(.ui-content) > .ui-btn-right:first-child + img:last-child {
2386 -webkit-border-radius: inherit;
2387 border-radius: inherit;
2388}
2389.ui-popup iframe {
2390 vertical-align: middle;
2391}
2392@media all and (min-width: 28em){
2393 .ui-popup .ui-field-contain label.ui-submit,
2394 .ui-popup .ui-field-contain .ui-controlgroup-label,
2395 .ui-popup .ui-field-contain label.ui-select,
2396 .ui-popup .ui-field-contain label.ui-input-text {
2397 font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em;
2398 }
2399 .ui-popup .ui-field-contain .ui-btn.ui-submit,
2400 .ui-popup .ui-field-contain .ui-controlgroup-controls,
2401 .ui-popup .ui-field-contain .ui-select,
2402 .ui-popup .ui-field-contain input.ui-input-text,
2403 .ui-popup .ui-field-contain textarea.ui-input-text,
2404 .ui-popup .ui-field-contain .ui-input-search {
2405 width: 100%; display: block;
2406 }
2407}
2408.ui-popup > .ui-btn-left,
2409.ui-popup > .ui-btn-right {
2410 position: absolute;
2411 top: -9px;
2412 margin: 0;
2413 z-index: 1101;
2414}
2415.ui-popup > .ui-btn-left { left: -9px; }
2416.ui-popup > .ui-btn-right { right: -9px; }
2417.ui-popup-hidden { top: -99999px; left: -9999px; visibility: hidden; }
2418.ui-checkbox, .ui-radio { position: relative; clear: both; margin: 0; z-index: 1; }
2419.ui-checkbox .ui-btn, .ui-radio .ui-btn { text-align: left; z-index: 2; }
2420.ui-controlgroup .ui-checkbox .ui-btn, .ui-controlgroup .ui-radio .ui-btn { margin: 0; }
2421.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }
2422.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }
2423.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; }
2424.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
2425.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; }
2426.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; }
2427.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; }
2428.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }
2429.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon { left: 15px; }
2430.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon, .ui-radio .ui-mini.ui-btn-icon-left .ui-icon { left: 9px; }
2431.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
2432.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
2433.ui-checkbox .ui-btn-icon-top .ui-icon, .ui-radio .ui-btn-icon-top .ui-icon { top: 10px; }
2434.ui-checkbox .ui-btn-icon-bottom .ui-icon, .ui-radio .ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
2435.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
2436.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
2437.ui-controlgroup-horizontal .ui-checkbox .ui-icon,
2438.ui-controlgroup-horizontal .ui-radio .ui-icon { display: none; }
2439.ui-controlgroup-horizontal .ui-checkbox .ui-btn-inner,
2440.ui-controlgroup-horizontal .ui-radio .ui-btn-inner { padding: .6em 20px; }
2441.ui-controlgroup-horizontal .ui-checkbox .ui-mini .ui-btn-inner,
2442.ui-controlgroup-horizontal .ui-radio .ui-mini .ui-btn-inner { padding: .55em 11px .5em; }
2443/* input, label positioning */
2444.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; }
2445.ui-field-contain, fieldset.ui-field-contain { padding: .8em 0; margin: 0; border-width: 0 0 1px 0; overflow: visible; }
2446.ui-field-contain:last-child { border-bottom-width: 0; }
2447.ui-field-contain { max-width: 100%; } /* This prevents horizontal scrollbar in IE7 */
2448@media all and (min-width: 28em){
2449 .ui-field-contain, .ui-mobile fieldset.ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
2450}
2451.ui-select { display: block; position: relative; }
2452.ui-select select { position: absolute; left: -9999px; top: -9999px; }
2453.ui-select .ui-btn { opacity: 1; }
2454.ui-field-contain .ui-select .ui-btn { margin: 0; }
2455/* 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. */
2456.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%; filter: Alpha(Opacity=0); opacity: 0; z-index: 2; }
2457.ui-select .ui-disabled { opacity: .3; }
2458/* Display none because of issues with IE/WP's filter alpha opacity */
2459.ui-select .ui-disabled select { display: none; }
2460@-moz-document url-prefix() { .ui-select .ui-btn select { opacity: 0.0001; }}
2461.ui-select .ui-btn.ui-select-nativeonly { border-radius: 0; border: 0; }
2462.ui-select .ui-btn.ui-select-nativeonly select { opacity: 1; text-indent: 0; display: block; }
2463.ui-select .ui-disabled.ui-select-nativeonly .ui-btn-inner { opacity: 0; }
2464.ui-select .ui-btn-icon-right .ui-btn-inner, .ui-select .ui-li-has-count .ui-btn-inner { padding-right: 45px; }
2465.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner { padding-right: 32px; }
2466.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 80px; }
2467.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 67px; }
2468.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
2469.ui-select .ui-mini.ui-btn-icon-right .ui-icon { right: 7px; }
2470.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 45px; }
2471.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 32px; }
2472/* labels */
2473label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
2474/*listbox*/
2475.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: block; min-height: 1em; overflow: hidden !important;
2476/* This !important is required for iPad Safari specifically. See https://github.com/jquery/jquery-mobile/issues/2647 */ }
2477.ui-select .ui-btn-text { text-overflow: ellipsis; }
2478.ui-selectmenu { padding: 6px; min-width: 160px; }
2479.ui-selectmenu .ui-listview { margin: 0; }
2480.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }
2481.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }
2482.ui-selectmenu-list .ui-li .ui-icon { display: block; }
2483.ui-li.ui-selectmenu-placeholder { display: none; }
2484.ui-selectmenu .ui-header { margin: 0; padding: 0; }
2485.ui-selectmenu.ui-popup .ui-header { -webkit-border-top-left-radius: 0; border-top-left-radius: 0; -webkit-border-top-right-radius: 0; border-top-right-radius: 0; }
2486.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }
2487@media all and (min-width: 28em){
2488 .ui-field-contain label.ui-select { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
2489 .ui-field-contain .ui-select { width: 78%; display: inline-block; }
2490 .ui-hide-label .ui-select { width: 100%; }
2491}
2492/* 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 */
2493.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }
2494label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; }
2495input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; margin: .5em 0; min-height: 1.4em; line-height: 1.4em; font-size: 16px; display: block; width: 100%; outline: 0; }
2496input.ui-mini, .ui-mini input, textarea.ui-mini { font-size: 14px; }
2497div.ui-input-text input.ui-input-text, div.ui-input-text textarea.ui-input-text,
2498.ui-input-search input.ui-input-text { border: none; width: 100%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }
2499.ui-input-search, div.ui-input-text { margin: .5em 0; background-image: none; position: relative; }
2500.ui-input-search { padding: 0 30px; }
2501div.ui-input-text { padding: 0 .4em; }
2502div.ui-input-has-clear { padding: 0 30px 0 .4em; }
2503input.ui-input-text.ui-mini, textarea.ui-input-text.ui-mini,
2504.ui-input-search.ui-mini, div.ui-input-text.ui-mini { margin: .25em 0; }
2505.ui-field-contain input.ui-input-text, .ui-field-contain textarea.ui-input-text,
2506.ui-field-contain .ui-input-search, .ui-field-contain div.ui-input-text { margin: 0; }
2507textarea.ui-input-text { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
2508input.ui-input-text { -webkit-appearance: none; }
2509textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }
2510textarea.ui-mini { height: 45px; }
2511.ui-icon-searchfield:after { position: absolute; left: 7px; top: 50%; margin-top: -9px; content: ""; width: 18px; height: 18px; opacity: .5; }
2512.ui-input-search .ui-input-clear, .ui-input-text .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -13px; }
2513.ui-mini .ui-input-clear { right: -3px; }
2514.ui-input-search .ui-input-clear-hidden, .ui-input-text .ui-input-clear-hidden { display: none; }
2515/* Resolves issue #5166: Added to support issue introduced in Firefox 15. We can likely remove this in the future. */
2516input::-moz-placeholder, textarea::-moz-placeholder { color: #aaa; }
2517/* For IE10 */
2518:-ms-input-placeholder { color: #aaa; }
2519/* Resolves issue #5131: Width of textinput depends on its type, for Android 4.1 */
2520input[type=number]::-webkit-outer-spin-button { margin: 0; }
2521@media all and (min-width: 28em){
2522 .ui-field-contain label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }
2523 .ui-field-contain input.ui-input-text,
2524 .ui-field-contain textarea.ui-input-text,
2525 .ui-field-contain .ui-input-search,
2526 .ui-field-contain div.ui-input-text { width: 78%; display: inline-block; }
2527 .ui-field-contain .ui-input-search,
2528 .ui-field-contain div.ui-input-text { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
2529 .ui-hide-label input.ui-input-text,
2530 .ui-hide-label textarea.ui-input-text,
2531 .ui-hide-label .ui-input-search,
2532 .ui-hide-label div.ui-input-text,
2533 .ui-input-search input.ui-input-text,
2534 div.ui-input-text input.ui-input-text { width: 100%; }
2535}
2536.ui-rangeslider {
2537 zoom: 1;
2538 margin: 0;
2539}
2540.ui-rangeslider:before,
2541.ui-rangeslider:after {
2542 content: "";
2543 display: table;
2544}
2545.ui-rangeslider:after {
2546 clear: both;
2547}
2548/* Margin-top/bottom: .5em * 16px/14px to make it equal to ui-rangeslider-sliders margin (input font-size is 14px) */
2549.ui-rangeslider input.ui-input-text.ui-slider-input {
2550 margin: .57143em 0;
2551}
2552.ui-rangeslider.ui-mini input.ui-slider-input {
2553 margin: .28571em 0;
2554}
2555.ui-rangeslider input.ui-slider-input.ui-rangeslider-last {
2556 float: right;
2557}
2558.ui-rangeslider .ui-rangeslider-sliders {
2559 position: relative;
2560 overflow: visible;
2561 height: 30px;
2562 margin: .5em 68px;
2563}
2564.ui-rangeslider.ui-mini .ui-rangeslider-sliders {
2565 margin: .25em 68px;
2566}
2567.ui-field-contain .ui-rangeslider input.ui-slider-input,
2568.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input,
2569.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,
2570.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
2571 margin-top: 0;
2572 margin-bottom: 0;
2573}
2574.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track {
2575 position: absolute;
2576 top: 6px;
2577 right: 0;
2578 left: 0;
2579 margin: 0;
2580}
2581.ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track {
2582 top: 8px;
2583}
2584.ui-rangeslider .ui-slider-track:first-child .ui-slider-bg {
2585 display: none;
2586}
2587.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child {
2588 background-color: transparent;
2589 background: none;
2590 border-width: 0;
2591 height: 0;
2592}
2593/* this makes ie6 and ie7 set height to 0 to fix z-index problem */
2594html >/**/body .ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child {
2595 height: 15px;
2596 border-width: 1px;
2597}
2598html >/**/body .ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track:first-child {
2599 height: 12px;
2600}
2601@media all and (min-width: 28em){
2602 .ui-field-contain .ui-rangeslider label.ui-slider {
2603 float: left;
2604 }
2605 .ui-field-contain .ui-rangeslider input.ui-slider-input {
2606 position: relative;
2607 z-index: 1;
2608 }
2609 .ui-field-contain .ui-rangeslider input.ui-slider-input.ui-rangeslider-first,
2610 .ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input.ui-rangeslider-first {
2611 margin-right: 17px;
2612 }
2613 .ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,
2614 .ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
2615 float: left;
2616 width: 78%;
2617 margin: 0 -68px;
2618 }
2619 .ui-field-contain .ui-rangeslider .ui-slider-track,
2620 .ui-field-contain .ui-rangeslider.ui-mini .ui-slider-track {
2621 right: 68px;
2622 left: 68px;
2623 }
2624 .ui-field-contain.ui-hide-label .ui-rangeslider input.ui-slider-input.ui-rangeslider-first {
2625 margin: 0;
2626 }
2627 .ui-field-contain.ui-hide-label .ui-rangeslider .ui-rangeslider-sliders,
2628 .ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
2629 width: auto;
2630 float: none;
2631 margin: 0 68px;
2632 }
2633 .ui-field-contain.ui-hide-label .ui-rangeslider .ui-slider-track,
2634 .ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-slider-track {
2635 right: 0;
2636 left: 0;
2637 }
2638}
2639.ui-listview { margin: 0; }
2640ol.ui-listview, ol.ui-listview .ui-li-divider { counter-reset: listnumbering; }
2641.ui-content .ui-listview, .ui-panel-inner > .ui-listview { margin: -15px; }
2642.ui-collapsible-content > .ui-listview { margin: -10px -15px; }
2643.ui-content .ui-listview-inset, .ui-panel-inner .ui-listview-inset { margin: 1em 0; }
2644.ui-collapsible-content .ui-listview-inset { margin: .5em 0; }
2645.ui-listview, .ui-li { list-style: none; padding: 0; }
2646.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; }
2647.ui-li.ui-btn, .ui-li.ui-field-contain, .ui-li-divider, .ui-li-static { margin: 0; }
2648.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }
2649.ui-li.ui-last-child, .ui-li.ui-field-contain.ui-last-child { border-bottom-width: 1px; }
2650.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) > .ui-li.ui-first-child { border-top-width: 0; }
2651.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset) > .ui-li.ui-last-child { border-bottom-width: 0; }
2652.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
2653.ui-li-static { background-image: none; }
2654.ui-li-divider { padding: .5em 15px; font-size: 14px; font-weight: bold; }
2655ol.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) ". "; }
2656ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */
2657.ui-listview .ui-li > .ui-btn-text {
2658 -webkit-border-radius: inherit;
2659 border-radius: inherit;
2660}
2661.ui-listview > .ui-li.ui-first-child,
2662.ui-listview .ui-btn.ui-first-child > .ui-li > .ui-btn-text > .ui-link-inherit {
2663 -webkit-border-top-right-radius: inherit;
2664 border-top-right-radius: inherit;
2665 -webkit-border-top-left-radius: inherit;
2666 border-top-left-radius: inherit;
2667}
2668.ui-listview > .ui-li.ui-last-child,
2669.ui-listview .ui-btn.ui-last-child > .ui-li > .ui-btn-text > .ui-link-inherit,
2670.ui-collapsible-content > .ui-listview:not(.ui-listview-inset),
2671.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li.ui-last-child {
2672 -webkit-border-bottom-right-radius: inherit;
2673 border-bottom-right-radius: inherit;
2674 -webkit-border-bottom-left-radius: inherit;
2675 border-bottom-left-radius: inherit;
2676}
2677.ui-listview > .ui-li.ui-first-child .ui-li-link-alt {
2678 -webkit-border-top-right-radius: inherit;
2679 border-top-right-radius: inherit;
2680}
2681.ui-listview > .ui-li.ui-last-child .ui-li-link-alt {
2682 -webkit-border-bottom-right-radius: inherit;
2683 border-bottom-right-radius: inherit;
2684}
2685.ui-listview > .ui-li.ui-first-child .ui-li-thumb:not(.ui-li-icon) {
2686 -webkit-border-top-left-radius: inherit;
2687 border-top-left-radius: inherit;
2688}
2689.ui-listview > .ui-li.ui-last-child .ui-li-thumb:not(.ui-li-icon) {
2690 -webkit-border-bottom-left-radius: inherit;
2691 border-bottom-left-radius: inherit;
2692}
2693.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }
2694.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 15px; display: block; }
2695.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 59px; padding-left: 100px; }
2696.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }
2697.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; }
2698.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow { padding-right: 40px; }
2699.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; }
2700.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
2701.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
2702ol.ui-listview > .ui-li .ui-li-heading { display: inline-block; width: 100%; margin-left: -1.3em; text-indent: 1.3em; vertical-align: middle; }
2703ol.ui-listview > .ui-li .ui-li-desc:not(.ui-li-aside) { text-indent: 1.55em; }
2704.ui-li-thumb, .ui-listview .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }
2705.ui-listview .ui-li-icon { max-height: 16px; max-width: 16px; left: 10px; top: .9em; }
2706.ui-li-thumb, .ui-listview .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }
2707.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
2708@media all and (min-width: 480px){
2709 .ui-li-aside { width: 45%; }
2710}
2711.ui-li-divider { cursor: default; }
2712.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 53px; }
2713.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; }
2714.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; }
2715.ui-li-has-count.ui-li-divider .ui-li-count, .ui-li-has-count .ui-link-inherit .ui-li-count { margin-top: -.95em; }
2716.ui-li-has-arrow.ui-li-has-count .ui-li-count { right: 40px; }
2717.ui-li-has-alt.ui-li-has-count .ui-li-count { right: 53px; }
2718.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; }
2719.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;}
2720.ui-li-link-alt .ui-btn-inner { padding: 0; height: 100%; position: absolute; width: 100%; top: 0; left: 0;}
2721.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }
2722.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
2723.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner { border-top: 0; }
2724.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px; }
2725.ui-collapsible-content .ui-listview-filter { margin: -10px -15px 10px -15px; border-bottom: inherit; }
2726.ui-listview-filter-inset { margin: -15px -5px; background: transparent; }
2727.ui-collapsible-content .ui-listview-filter-inset { margin: -5px; border-bottom-width: 0; }
2728.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }
2729.ui-li.ui-screen-hidden{ display:none; }
2730/* Odd iPad positioning issue. */
2731@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
2732 .ui-li .ui-btn-text { overflow: visible; }
2733}
2734label.ui-slider {
2735 font-size: 16px;
2736 line-height: 1.4;
2737 font-weight: normal;
2738 margin: 0;
2739 display: block;
2740}
2741.ui-field-contain label.ui-slider {
2742 margin-bottom: .4em;
2743}
2744div.ui-slider {
2745 height: 30px;
2746 margin: .5em 0;
2747 zoom: 1;
2748}
2749div.ui-slider.ui-mini {
2750 margin: .25em 0;
2751}
2752.ui-field-contain div.ui-slider,
2753.ui-field-contain div.ui-slider.ui-mini {
2754 margin: 0;
2755}
2756div.ui-slider:before, div.ui-slider:after {
2757 content: "";
2758 display: table;
2759}
2760div.ui-slider:after {
2761 clear: both;
2762}
2763/* High level of specificity to override Textinput CSS. */
2764input.ui-input-text.ui-slider-input {
2765 display: block;
2766 float: left;
2767 margin: 0;
2768 padding: 4px;
2769 width: 40px;
2770 height: 22px;
2771 line-height: 22px;
2772 font-size: 14px;
2773 border-width: 0;
2774 background-image: none;
2775 font-weight: bold;
2776 text-align: center;
2777 vertical-align: text-bottom;
2778 outline: 0;
2779 -webkit-box-sizing: content-box;
2780 -moz-box-sizing: content-box;
2781 -ms-box-sizing: content-box;
2782 box-sizing: content-box;
2783}
2784.ui-slider-input::-webkit-outer-spin-button,
2785.ui-slider-input::-webkit-inner-spin-button {
2786 -webkit-appearance: none;
2787 margin: 0;
2788}
2789.ui-slider-track,
2790.ui-slider-switch {
2791 position: relative;
2792 overflow: visible;
2793 height: 15px;
2794 margin: 0 15px 0 68px;
2795 top: 6px;
2796}
2797.ui-slider-track.ui-mini {
2798 height: 12px;
2799 top: 8px;
2800}
2801.ui-slider-bg {
2802 border: none;
2803 height: 100%;
2804}
2805/* High level of specificity to override button margins in grids */
2806.ui-slider-track .ui-btn.ui-slider-handle,
2807.ui-slider-switch .ui-btn.ui-slider-handle {
2808 position: absolute;
2809 z-index: 1;
2810 top: 50%;
2811 width: 28px;
2812 height: 28px;
2813 margin: -15px 0 0 -15px;
2814 outline: 0;
2815}
2816.ui-slider-track.ui-mini .ui-slider-handle {
2817 height: 14px;
2818 width: 14px;
2819 margin: -8px 0 0 -7px;
2820}
2821.ui-slider-handle .ui-btn-inner {
2822 padding: 0;
2823 height: 100%;
2824}
2825.ui-slider-track.ui-mini .ui-slider-handle .ui-btn-inner {
2826 height: 30px;
2827 width: 30px;
2828 padding: 0;
2829 margin: -9px 0 0 -9px;
2830 border-top: none;
2831}
2832select.ui-slider-switch {
2833 display: none;
2834}
2835div.ui-slider-switch {
2836 display: inline-block;
2837 height: 32px;
2838 width: 5.8em;
2839 margin: .5em 0;
2840 top: 0;
2841}
2842/* reset the clearfix */
2843div.ui-slider-switch:before, div.ui-slider-switch:after {
2844 display: none;
2845 clear: none;
2846}
2847div.ui-slider-switch.ui-mini {
2848 width: 5em;
2849 height: 29px;
2850 margin: .25em 0;
2851 top: 0;
2852}
2853.ui-field-contain .ui-slider-switch,
2854.ui-field-contain .ui-slider-switch.ui-mini {
2855 margin: 0;
2856}
2857.ui-slider-inneroffset {
2858 margin: 0 16px;
2859 position: relative;
2860 z-index: 1;
2861}
2862.ui-slider-switch.ui-mini .ui-slider-inneroffset {
2863 margin: 0 15px 0 14px;
2864}
2865.ui-slider-switch .ui-btn.ui-slider-handle {
2866 margin: 1px 0 0 -15px;
2867}
2868.ui-slider-switch.ui-mini .ui-slider-handle {
2869 width: 25px;
2870 height: 25px;
2871 margin: 1px 0 0 -13px;
2872 padding: 0;
2873}
2874.ui-slider-handle-snapping {
2875 -webkit-transition: left 70ms linear;
2876 -moz-transition: left 70ms linear;
2877}
2878.ui-slider-switch.ui-mini .ui-slider-handle .ui-btn-inner {
2879 height: 30px;
2880 width: 30px;
2881 padding: 0;
2882 margin: 0;
2883 border-top: none;
2884}
2885.ui-slider-switch .ui-slider-label {
2886 position: absolute;
2887 text-align: center;
2888 width: 100%;
2889 overflow: hidden;
2890 font-size: 16px;
2891 top: 0;
2892 line-height: 2;
2893 min-height: 100%;
2894 border-width: 0;
2895 white-space: nowrap;
2896 cursor: pointer;
2897}
2898.ui-slider-switch.ui-mini .ui-slider-label {
2899 font-size: 14px;
2900}
2901.ui-slider-switch .ui-slider-label-a {
2902 z-index: 1;
2903 left: 0;
2904 text-indent: -1.5em;
2905}
2906.ui-slider-switch .ui-slider-label-b {
2907 z-index: 0;
2908 right: 0;
2909 text-indent: 1.5em;
2910}
2911@media all and (min-width: 28em){
2912 .ui-field-contain label.ui-slider {
2913 vertical-align: top;
2914 display: inline-block;
2915 width: 20%;
2916 margin: 0 2% 0 0;
2917 }
2918 .ui-field-contain div.ui-slider {
2919 display: inline-block;
2920 width: 78%;
2921 }
2922 .ui-field-contain.ui-hide-label div.ui-slider {
2923 display: block;
2924 width: auto;
2925 }
2926 .ui-field-contain div.ui-slider-switch,
2927 .ui-field-contain.ui-hide-label div.ui-slider-switch {
2928 display: inline-block;
2929 width: 5.8em;
2930 }
2931 .ui-field-contain div.ui-slider-switch.ui-mini {
2932 width: 5em;
2933 }
2934}
2935.ui-table {
2936 border: 0;
2937 border-collapse: collapse;
2938 padding: 0;
2939 width: 100%;
2940}
2941.ui-table th,
2942.ui-table td {
2943 line-height: 1.5em;
2944 text-align: left;
2945 padding: .4em .5em;
2946 vertical-align:top;
2947}
2948.ui-table th .ui-btn,
2949.ui-table td .ui-btn {
2950 line-height: normal;
2951}
2952.ui-table th {
2953 font-weight: bold;
2954}
2955.ui-table caption {
2956 text-align:left;
2957 margin-bottom:1.4em;
2958 opacity: .5;
2959}
2960/* Add strokes between each row */
2961.table-stroke thead th {
2962 border-bottom: 1px solid #d6d6d6; /* non-RGBA fallback */
2963 border-bottom: 1px solid rgba(0, 0, 0, .1);
2964}
2965.table-stroke tbody th,
2966.table-stroke tbody td {
2967 border-bottom: 1px solid #e6e6e6; /* non-RGBA fallback */
2968 border-bottom: 1px solid rgba(0, 0, 0, .05);
2969}
2970/* Add alternating row stripes */
2971.table-stripe tbody tr:nth-child(odd) td,
2972.table-stripe tbody tr:nth-child(odd) th {
2973 background-color: #eeeeee; /* non-RGBA fallback */
2974 background-color: rgba(0,0,0,0.04);
2975}
2976/* Add stroke to the header and last item */
2977.table-stripe thead th,
2978.table-stripe tbody tr:last-child {
2979 border-bottom: 1px solid #d6d6d6; /* non-RGBA fallback */
2980 border-bottom: 1px solid rgba(0, 0, 0, .1);
2981}
2982/*
2983 Styles for the table columntoggle mode
2984*/
2985.ui-table-columntoggle-btn {
2986 float: right;
2987 margin-bottom:.8em;
2988}
2989/* Remove top/bottom margins around the fieldcontain on check list */
2990.ui-table-columntoggle-popup fieldset {
2991 margin:0;
2992}
2993/* Hide all prioritized columns by default */
2994@media only all {
2995 th.ui-table-priority-6,
2996 td.ui-table-priority-6,
2997 th.ui-table-priority-5,
2998 td.ui-table-priority-5,
2999 th.ui-table-priority-4,
3000 td.ui-table-priority-4,
3001 th.ui-table-priority-3,
3002 td.ui-table-priority-3,
3003 th.ui-table-priority-2,
3004 td.ui-table-priority-2,
3005 th.ui-table-priority-1,
3006 td.ui-table-priority-1 {
3007 display: none;
3008 }
3009}
3010/* Preset breakpoints if ".ui-responsive" class added to table */
3011/* Show priority 1 at 320px (20em x 16px) */
3012@media screen and (min-width: 20em) {
3013 .ui-table-columntoggle.ui-responsive th.ui-table-priority-1,
3014 .ui-table-columntoggle.ui-responsive td.ui-table-priority-1 {
3015 display: table-cell;
3016 }
3017}
3018/* Show priority 2 at 480px (30em x 16px) */
3019@media screen and (min-width: 30em) {
3020 .ui-table-columntoggle.ui-responsive th.ui-table-priority-2,
3021 .ui-table-columntoggle.ui-responsive td.ui-table-priority-2 {
3022 display: table-cell;
3023 }
3024}
3025/* Show priority 3 at 640px (40em x 16px) */
3026@media screen and (min-width: 40em) {
3027 .ui-table-columntoggle.ui-responsive th.ui-table-priority-3,
3028 .ui-table-columntoggle.ui-responsive td.ui-table-priority-3 {
3029 display: table-cell;
3030 }
3031}
3032/* Show priority 4 at 800px (50em x 16px) */
3033@media screen and (min-width: 50em) {
3034 .ui-table-columntoggle.ui-responsive th.ui-table-priority-4,
3035 .ui-table-columntoggle.ui-responsive td.ui-table-priority-4 {
3036 display: table-cell;
3037 }
3038}
3039/* Show priority 5 at 960px (60em x 16px) */
3040@media screen and (min-width: 60em) {
3041 .ui-table-columntoggle.ui-responsive th.ui-table-priority-5,
3042 .ui-table-columntoggle.ui-responsive td.ui-table-priority-5 {
3043 display: table-cell;
3044 }
3045}
3046/* Show priority 6 at 1,120px (70em x 16px) */
3047@media screen and (min-width: 70em) {
3048 .ui-table-columntoggle.ui-responsive th.ui-table-priority-6,
3049 .ui-table-columntoggle.ui-responsive td.ui-table-priority-6 {
3050 display: table-cell;
3051 }
3052}
3053/* Unchecked manually: Always hide */
3054.ui-table-columntoggle th.ui-table-cell-hidden,
3055.ui-table-columntoggle td.ui-table-cell-hidden,
3056.ui-table-columntoggle.ui-responsive th.ui-table-cell-hidden,
3057.ui-table-columntoggle.ui-responsive td.ui-table-cell-hidden {
3058 display: none;
3059}
3060/* Checked manually: Always show */
3061.ui-table-columntoggle th.ui-table-cell-visible,
3062.ui-table-columntoggle td.ui-table-cell-visible,
3063.ui-table-columntoggle.ui-responsive th.ui-table-cell-visible,
3064.ui-table-columntoggle.ui-responsive td.ui-table-cell-visible {
3065 display: table-cell;
3066}
3067/*
3068 Styles for the table columntoggle mode
3069*/
3070.ui-table-reflow td .ui-table-cell-label,
3071.ui-table-reflow th .ui-table-cell-label {
3072 display: none;
3073}
3074/* Mobile first styles: Begin with the stacked presentation at narrow widths */
3075@media only all {
3076 /* Hide the table headers */
3077 .ui-table-reflow thead td,
3078 .ui-table-reflow thead th {
3079 display: none;
3080 }
3081 /* Show the table cells as a block level element */
3082 .ui-table-reflow td,
3083 .ui-table-reflow th {
3084 text-align: left;
3085 display: block;
3086 }
3087 /* Add a fair amount of top margin to visually separate each row when stacked */
3088 .ui-table-reflow tbody th {
3089 margin-top: 3em;
3090 }
3091 /* Make the label elements a percentage width */
3092 .ui-table-reflow td .ui-table-cell-label,
3093 .ui-table-reflow th .ui-table-cell-label {
3094 padding: .4em;
3095 min-width: 30%;
3096 display: inline-block;
3097 margin: -.4em 1em -.4em -.4em;
3098 }
3099 /* For grouped headers, have a different style to visually separate the levels by classing the first label in each col group */
3100 .ui-table-reflow th .ui-table-cell-label-top,
3101 .ui-table-reflow td .ui-table-cell-label-top {
3102 display: block;
3103 padding: .4em 0;
3104 margin: .4em 0;
3105 text-transform: uppercase;
3106 font-size: .9em;
3107 font-weight: normal;
3108 }
3109}
3110/* Breakpoint to show as a standard table at 560px (35em x 16px) or wider */
3111@media ( min-width: 35em ) {
3112 /* Fixes table rendering when switching between breakpoints in Safari <= 5. See https://github.com/jquery/jquery-mobile/issues/5380 */
3113 .ui-table-reflow.ui-responsive {
3114 display: table-row-group;
3115 }
3116 /* Show the table header rows */
3117 .ui-table-reflow.ui-responsive td,
3118 .ui-table-reflow.ui-responsive th,
3119 .ui-table-reflow.ui-responsive tbody th,
3120 .ui-table-reflow.ui-responsive tbody td,
3121 .ui-table-reflow.ui-responsive thead td,
3122 .ui-table-reflow.ui-responsive thead th {
3123 display: table-cell;
3124 margin: 0;
3125 }
3126 /* Hide the labels in each cell */
3127 .ui-table-reflow.ui-responsive td .ui-table-cell-label,
3128 .ui-table-reflow.ui-responsive th .ui-table-cell-label {
3129 display: none;
3130 }
3131}
3132/* Hack to make IE9 and WP7.5 treat cells like block level elements, scoped to ui-responsive class */
3133/* Applied in a max-width media query up to the table layout breakpoint so we don't need to negate this*/
3134@media ( max-width: 35em ) {
3135 .ui-table-reflow.ui-responsive td,
3136 .ui-table-reflow.ui-responsive th {
3137 width: 100%;
3138 -webkit-box-sizing: border-box;
3139 -moz-box-sizing: border-box;
3140 box-sizing: border-box;
3141 float: left;
3142 clear: left;
3143 }
3144}
3145/* panel */
3146.ui-panel {
3147 width: 17em;
3148 min-height: 100%;
3149 max-height: none;
3150 border-width: 0;
3151 position: absolute;
3152 top: 0;
3153 display: block;
3154}
3155.ui-panel-closed {
3156 width: 0;
3157 max-height: 100%;
3158 overflow: hidden;
3159 visibility: hidden;
3160}
3161.ui-panel-fixed {
3162 position: fixed;
3163 bottom: -1px; /* fixes gap on Chrome for Android */
3164 padding-bottom: 1px;
3165}
3166.ui-panel-display-overlay {
3167 z-index: 1001; /* fixed toolbars have z-index 1000 */
3168}
3169.ui-panel-display-reveal {
3170 z-index: 0;
3171}
3172.ui-panel-display-push {
3173 z-index: 999;
3174}
3175.ui-panel-inner {
3176 padding: 15px;
3177}
3178/* content-wrap */
3179.ui-panel-content-wrap {
3180 position: relative;
3181 left: 0;
3182 min-height: inherit;
3183 border: none;
3184 z-index: 999;
3185}
3186.ui-panel-content-wrap-display-overlay,
3187.ui-panel-animate.ui-panel-content-wrap > .ui-header, /* ios4 fix */
3188.ui-panel-content-wrap-closed {
3189 position: static;
3190}
3191/* dismiss */
3192.ui-panel-dismiss {
3193 position: absolute;
3194 top: 0;
3195 left:0;
3196 height: 100%;
3197 width: 100%;
3198 z-index: 1002;
3199 display: none;
3200}
3201.ui-panel-dismiss-open {
3202 display: block;
3203}
3204/* animate class is added to panel, wrapper and fixed toolbars */
3205.ui-panel-animate {
3206 -webkit-transition: -webkit-transform 350ms ease;
3207 -moz-transition: -moz-transform 350ms ease;
3208 transition: transform 350ms ease;
3209}
3210/* hardware acceleration for smoother transitions on WebKit browsers */
3211.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal),
3212.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal) > div,
3213.ui-panel-animate.ui-panel-closed.ui-panel-display-reveal > div,
3214.ui-panel-animate.ui-panel-content-wrap,
3215.ui-panel-animate.ui-panel-content-fixed-toolbar {
3216 -webkit-backface-visibility: hidden;
3217 -webkit-transform: translate3d(0,0,0);
3218}
3219/* positioning: panel */
3220/* panel left */
3221.ui-panel-position-left {
3222 left: -17em;
3223}
3224/* animated: panel left (for overlay and push) */
3225.ui-panel-animate.ui-panel-position-left.ui-panel-display-overlay,
3226.ui-panel-animate.ui-panel-position-left.ui-panel-display-push {
3227 left: 0;
3228 -webkit-transform: translate3d(-17em,0,0);
3229 -moz-transform: translate3d(-17em,0,0);
3230 transform: translate3d(-17em,0,0);
3231}
3232/* panel left open */
3233.ui-panel-position-left.ui-panel-display-reveal, /* negate "panel left" for reveal */
3234.ui-panel-position-left.ui-panel-open {
3235 left: 0;
3236}
3237/* animated: panel left open (for overlay and push) */
3238.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-overlay,
3239.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-push {
3240 -webkit-transform: translate3d(0,0,0);
3241 transform: translate3d(0,0,0);
3242 -moz-transform: none;
3243}
3244/* panel right */
3245.ui-panel-position-right {
3246 right: -17em;
3247}
3248/* animated: panel right (for overlay and push) */
3249.ui-panel-animate.ui-panel-position-right.ui-panel-display-overlay,
3250.ui-panel-animate.ui-panel-position-right.ui-panel-display-push {
3251 right: 0;
3252 -webkit-transform: translate3d(17em,0,0);
3253 -moz-transform: translate3d(17em,0,0);
3254 transform: translate3d(17em,0,0);
3255}
3256/* panel right open */
3257.ui-panel-position-right.ui-panel-display-reveal, /* negate "panel right" for reveal */
3258.ui-panel-position-right.ui-panel-open {
3259 right: 0;
3260}
3261/* animated: panel right open (for overlay and push) */
3262.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-overlay,
3263.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-push {
3264 -webkit-transform: translate3d(0,0,0);
3265 transform: translate3d(0,0,0);
3266 -moz-transform: none;
3267}
3268/* positioning: content wrap, fixed toolbars and dismiss */
3269/* panel left open */
3270.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open,
3271.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open,
3272.ui-panel-dismiss-position-left.ui-panel-dismiss-open {
3273 left: 17em;
3274 right: -17em;
3275}
3276/* animated: panel left open (for reveal and push) */
3277.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,
3278.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,
3279.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,
3280.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push {
3281 left: 0;
3282 right: 0;
3283 -webkit-transform: translate3d(17em,0,0);
3284 -moz-transform: translate3d(17em,0,0);
3285 transform: translate3d(17em,0,0);
3286}
3287/* panel right open */
3288.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open,
3289.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open,
3290.ui-panel-dismiss-position-right.ui-panel-dismiss-open {
3291 left: -17em;
3292 right: 17em;
3293}
3294/* animated: panel right open (for reveal and push) */
3295.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,
3296.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,
3297.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,
3298.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push {
3299 left: 0;
3300 right: 0;
3301 -webkit-transform: translate3d(-17em,0,0);
3302 -moz-transform: translate3d(-17em,0,0);
3303 transform: translate3d(-17em,0,0);
3304}
3305/* negate "panel left/right open" for overlay */
3306.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-overlay,
3307.ui-panel-content-wrap-open.ui-panel-content-wrap-display-overlay {
3308 left: 0;
3309}
3310/* always disable overflow-x to prevent zoom issue on Android */
3311.ui-page-active.ui-page-panel {
3312 overflow-x: hidden;
3313}
3314/* shadows and borders */
3315.ui-panel-display-reveal {
3316 -webkit-box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
3317 -moz-box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
3318 box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
3319}
3320.ui-panel-position-right.ui-panel-display-reveal {
3321 -webkit-box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
3322 -moz-box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
3323 box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
3324}
3325.ui-panel-display-overlay {
3326 -webkit-box-shadow: 5px 0 5px rgba(0,0,0,.15);
3327 -moz-box-shadow: 5px 0 5px rgba(0,0,0,.15);
3328 box-shadow: 5px 0 5px rgba(0,0,0,.15);
3329}
3330.ui-panel-position-right.ui-panel-display-overlay {
3331 -webkit-box-shadow: -5px 0 5px rgba(0,0,0,.15);
3332 -moz-box-shadow: -5px 0 5px rgba(0,0,0,.15);
3333 box-shadow: -5px 0 5px rgba(0,0,0,.15);
3334}
3335.ui-panel-display-push.ui-panel-open.ui-panel-position-left {
3336 border-right-width: 1px;
3337 margin-right: -1px;
3338}
3339.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push {
3340 margin-left: 1px;
3341}
3342.ui-panel-display-push.ui-panel-open.ui-panel-position-right {
3343 border-left-width: 1px;
3344 margin-left: -1px;
3345}
3346.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push {
3347 margin-right: 1px;
3348}
3349/* wrap on wide viewports once open */
3350@media (min-width:55em){
3351 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-left,
3352 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-left,
3353 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-left,
3354 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-left {
3355 margin-right: 17em;
3356 }
3357 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-right,
3358 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-right,
3359 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-right,
3360 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-right {
3361 margin-left: 17em;
3362 }
3363 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push,
3364 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal {
3365 width: auto;
3366 }
3367 .ui-responsive-panel .ui-panel-dismiss-display-push {
3368 display: none;
3369 }
3370}
diff --git a/static/vendor/jquery.mobile-1.3.2.js b/static/vendor/jquery.mobile-1.3.2.js
deleted file mode 100644
index 6781bba..0000000
--- a/static/vendor/jquery.mobile-1.3.2.js
+++ /dev/null
@@ -1,11215 +0,0 @@
1/*!
2* jQuery Mobile 1.3.2
3* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
4* http://jquerymobile.com
5*
6* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
7* Released under the MIT license.
8* http://jquery.org/license
9*
10*/
11
12
13(function ( root, doc, factory ) {
14 if ( typeof define === "function" && define.amd ) {
15 // AMD. Register as an anonymous module.
16 define( [ "jquery" ], function ( $ ) {
17 factory( $, root, doc );
18 return $.mobile;
19 });
20 } else {
21 // Browser globals
22 factory( root.jQuery, root, doc );
23 }
24}( this, document, function ( jQuery, window, document, undefined ) {
25(function( $ ) {
26 $.mobile = {};
27}( jQuery ));
28(function( $, window, undefined ) {
29 var nsNormalizeDict = {};
30
31 // jQuery.mobile configurable options
32 $.mobile = $.extend($.mobile, {
33
34 // Version of the jQuery Mobile Framework
35 version: "1.3.2",
36
37 // Namespace used framework-wide for data-attrs. Default is no namespace
38 ns: "",
39
40 // Define the url parameter used for referencing widget-generated sub-pages.
41 // Translates to to example.html&ui-page=subpageIdentifier
42 // hash segment before &ui-page= is used to make Ajax request
43 subPageUrlKey: "ui-page",
44
45 // Class assigned to page currently in view, and during transitions
46 activePageClass: "ui-page-active",
47
48 // Class used for "active" button state, from CSS framework
49 activeBtnClass: "ui-btn-active",
50
51 // Class used for "focus" form element state, from CSS framework
52 focusClass: "ui-focus",
53
54 // Automatically handle clicks and form submissions through Ajax, when same-domain
55 ajaxEnabled: true,
56
57 // Automatically load and show pages based on location.hash
58 hashListeningEnabled: true,
59
60 // disable to prevent jquery from bothering with links
61 linkBindingEnabled: true,
62
63 // Set default page transition - 'none' for no transitions
64 defaultPageTransition: "fade",
65
66 // Set maximum window width for transitions to apply - 'false' for no limit
67 maxTransitionWidth: false,
68
69 // Minimum scroll distance that will be remembered when returning to a page
70 minScrollBack: 250,
71
72 // DEPRECATED: the following property is no longer in use, but defined until 2.0 to prevent conflicts
73 touchOverflowEnabled: false,
74
75 // Set default dialog transition - 'none' for no transitions
76 defaultDialogTransition: "pop",
77
78 // Error response message - appears when an Ajax page request fails
79 pageLoadErrorMessage: "Error Loading Page",
80
81 // For error messages, which theme does the box uses?
82 pageLoadErrorMessageTheme: "e",
83
84 // replace calls to window.history.back with phonegaps navigation helper
85 // where it is provided on the window object
86 phonegapNavigationEnabled: false,
87
88 //automatically initialize the DOM when it's ready
89 autoInitializePage: true,
90
91 pushStateEnabled: true,
92
93 // allows users to opt in to ignoring content by marking a parent element as
94 // data-ignored
95 ignoreContentEnabled: false,
96
97 // turn of binding to the native orientationchange due to android orientation behavior
98 orientationChangeEnabled: true,
99
100 buttonMarkup: {
101 hoverDelay: 200
102 },
103
104 // define the window and the document objects
105 window: $( window ),
106 document: $( document ),
107
108 // TODO might be useful upstream in jquery itself ?
109 keyCode: {
110 ALT: 18,
111 BACKSPACE: 8,
112 CAPS_LOCK: 20,
113 COMMA: 188,
114 COMMAND: 91,
115 COMMAND_LEFT: 91, // COMMAND
116 COMMAND_RIGHT: 93,
117 CONTROL: 17,
118 DELETE: 46,
119 DOWN: 40,
120 END: 35,
121 ENTER: 13,
122 ESCAPE: 27,
123 HOME: 36,
124 INSERT: 45,
125 LEFT: 37,
126 MENU: 93, // COMMAND_RIGHT
127 NUMPAD_ADD: 107,
128 NUMPAD_DECIMAL: 110,
129 NUMPAD_DIVIDE: 111,
130 NUMPAD_ENTER: 108,
131 NUMPAD_MULTIPLY: 106,
132 NUMPAD_SUBTRACT: 109,
133 PAGE_DOWN: 34,
134 PAGE_UP: 33,
135 PERIOD: 190,
136 RIGHT: 39,
137 SHIFT: 16,
138 SPACE: 32,
139 TAB: 9,
140 UP: 38,
141 WINDOWS: 91 // COMMAND
142 },
143
144 // Place to store various widget extensions
145 behaviors: {},
146
147 // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
148 silentScroll: function( ypos ) {
149 if ( $.type( ypos ) !== "number" ) {
150 ypos = $.mobile.defaultHomeScroll;
151 }
152
153 // prevent scrollstart and scrollstop events
154 $.event.special.scrollstart.enabled = false;
155
156 setTimeout( function() {
157 window.scrollTo( 0, ypos );
158 $.mobile.document.trigger( "silentscroll", { x: 0, y: ypos });
159 }, 20 );
160
161 setTimeout( function() {
162 $.event.special.scrollstart.enabled = true;
163 }, 150 );
164 },
165
166 // Expose our cache for testing purposes.
167 nsNormalizeDict: nsNormalizeDict,
168
169 // Take a data attribute property, prepend the namespace
170 // and then camel case the attribute string. Add the result
171 // to our nsNormalizeDict so we don't have to do this again.
172 nsNormalize: function( prop ) {
173 if ( !prop ) {
174 return;
175 }
176
177 return nsNormalizeDict[ prop ] || ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) );
178 },
179
180 // Find the closest parent with a theme class on it. Note that
181 // we are not using $.fn.closest() on purpose here because this
182 // method gets called quite a bit and we need it to be as fast
183 // as possible.
184 getInheritedTheme: function( el, defaultTheme ) {
185 var e = el[ 0 ],
186 ltr = "",
187 re = /ui-(bar|body|overlay)-([a-z])\b/,
188 c, m;
189
190 while ( e ) {
191 c = e.className || "";
192 if ( c && ( m = re.exec( c ) ) && ( ltr = m[ 2 ] ) ) {
193 // We found a parent with a theme class
194 // on it so bail from this loop.
195 break;
196 }
197
198 e = e.parentNode;
199 }
200
201 // Return the theme letter we found, if none, return the
202 // specified default.
203
204 return ltr || defaultTheme || "a";
205 },
206
207 // TODO the following $ and $.fn extensions can/probably should be moved into jquery.mobile.core.helpers
208 //
209 // Find the closest javascript page element to gather settings data jsperf test
210 // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit
211 // possibly naive, but it shows that the parsing overhead for *just* the page selector vs
212 // the page and dialog selector is negligable. This could probably be speed up by
213 // doing a similar parent node traversal to the one found in the inherited theme code above
214 closestPageData: function( $target ) {
215 return $target
216 .closest( ':jqmData(role="page"), :jqmData(role="dialog")' )
217 .data( "mobile-page" );
218 },
219
220 enhanceable: function( $set ) {
221 return this.haveParents( $set, "enhance" );
222 },
223
224 hijackable: function( $set ) {
225 return this.haveParents( $set, "ajax" );
226 },
227
228 haveParents: function( $set, attr ) {
229 if ( !$.mobile.ignoreContentEnabled ) {
230 return $set;
231 }
232
233 var count = $set.length,
234 $newSet = $(),
235 e, $element, excluded;
236
237 for ( var i = 0; i < count; i++ ) {
238 $element = $set.eq( i );
239 excluded = false;
240 e = $set[ i ];
241
242 while ( e ) {
243 var c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : "";
244
245 if ( c === "false" ) {
246 excluded = true;
247 break;
248 }
249
250 e = e.parentNode;
251 }
252
253 if ( !excluded ) {
254 $newSet = $newSet.add( $element );
255 }
256 }
257
258 return $newSet;
259 },
260
261 getScreenHeight: function() {
262 // Native innerHeight returns more accurate value for this across platforms,
263 // jQuery version is here as a normalized fallback for platforms like Symbian
264 return window.innerHeight || $.mobile.window.height();
265 }
266 }, $.mobile );
267
268 // Mobile version of data and removeData and hasData methods
269 // ensures all data is set and retrieved using jQuery Mobile's data namespace
270 $.fn.jqmData = function( prop, value ) {
271 var result;
272 if ( typeof prop !== "undefined" ) {
273 if ( prop ) {
274 prop = $.mobile.nsNormalize( prop );
275 }
276
277 // undefined is permitted as an explicit input for the second param
278 // in this case it returns the value and does not set it to undefined
279 if( arguments.length < 2 || value === undefined ){
280 result = this.data( prop );
281 } else {
282 result = this.data( prop, value );
283 }
284 }
285 return result;
286 };
287
288 $.jqmData = function( elem, prop, value ) {
289 var result;
290 if ( typeof prop !== "undefined" ) {
291 result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
292 }
293 return result;
294 };
295
296 $.fn.jqmRemoveData = function( prop ) {
297 return this.removeData( $.mobile.nsNormalize( prop ) );
298 };
299
300 $.jqmRemoveData = function( elem, prop ) {
301 return $.removeData( elem, $.mobile.nsNormalize( prop ) );
302 };
303
304 $.fn.removeWithDependents = function() {
305 $.removeWithDependents( this );
306 };
307
308 $.removeWithDependents = function( elem ) {
309 var $elem = $( elem );
310
311 ( $elem.jqmData( 'dependents' ) || $() ).remove();
312 $elem.remove();
313 };
314
315 $.fn.addDependents = function( newDependents ) {
316 $.addDependents( $( this ), newDependents );
317 };
318
319 $.addDependents = function( elem, newDependents ) {
320 var dependents = $( elem ).jqmData( 'dependents' ) || $();
321
322 $( elem ).jqmData( 'dependents', $.merge( dependents, newDependents ) );
323 };
324
325 // note that this helper doesn't attempt to handle the callback
326 // or setting of an html element's text, its only purpose is
327 // to return the html encoded version of the text in all cases. (thus the name)
328 $.fn.getEncodedText = function() {
329 return $( "<div/>" ).text( $( this ).text() ).html();
330 };
331
332 // fluent helper function for the mobile namespaced equivalent
333 $.fn.jqmEnhanceable = function() {
334 return $.mobile.enhanceable( this );
335 };
336
337 $.fn.jqmHijackable = function() {
338 return $.mobile.hijackable( this );
339 };
340
341 // Monkey-patching Sizzle to filter the :jqmData selector
342 var oldFind = $.find,
343 jqmDataRE = /:jqmData\(([^)]*)\)/g;
344
345 $.find = function( selector, context, ret, extra ) {
346 selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" );
347
348 return oldFind.call( this, selector, context, ret, extra );
349 };
350
351 $.extend( $.find, oldFind );
352
353 $.find.matches = function( expr, set ) {
354 return $.find( expr, null, null, set );
355 };
356
357 $.find.matchesSelector = function( node, expr ) {
358 return $.find( expr, null, null, [ node ] ).length > 0;
359 };
360})( jQuery, this );
361
362
363/*!
364 * jQuery UI Widget v1.10.0pre - 2012-11-13 (ff055a0c353c3c8ce6e5bfa07ad7cb03e8885bc5)
365 * http://jqueryui.com
366 *
367 * Copyright 2010, 2013 jQuery Foundation and other contributors
368 * Released under the MIT license.
369 * http://jquery.org/license
370 *
371 * http://api.jqueryui.com/jQuery.widget/
372 */
373(function( $, undefined ) {
374
375var uuid = 0,
376 slice = Array.prototype.slice,
377 _cleanData = $.cleanData;
378$.cleanData = function( elems ) {
379 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
380 try {
381 $( elem ).triggerHandler( "remove" );
382 // http://bugs.jquery.com/ticket/8235
383 } catch( e ) {}
384 }
385 _cleanData( elems );
386};
387
388$.widget = function( name, base, prototype ) {
389 var fullName, existingConstructor, constructor, basePrototype,
390 namespace = name.split( "." )[ 0 ];
391
392 name = name.split( "." )[ 1 ];
393 fullName = namespace + "-" + name;
394
395 if ( !prototype ) {
396 prototype = base;
397 base = $.Widget;
398 }
399
400 // create selector for plugin
401 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
402 return !!$.data( elem, fullName );
403 };
404
405 $[ namespace ] = $[ namespace ] || {};
406 existingConstructor = $[ namespace ][ name ];
407 constructor = $[ namespace ][ name ] = function( options, element ) {
408 // allow instantiation without "new" keyword
409 if ( !this._createWidget ) {
410 return new constructor( options, element );
411 }
412
413 // allow instantiation without initializing for simple inheritance
414 // must use "new" keyword (the code above always passes args)
415 if ( arguments.length ) {
416 this._createWidget( options, element );
417 }
418 };
419 // extend with the existing constructor to carry over any static properties
420 $.extend( constructor, existingConstructor, {
421 version: prototype.version,
422 // copy the object used to create the prototype in case we need to
423 // redefine the widget later
424 _proto: $.extend( {}, prototype ),
425 // track widgets that inherit from this widget in case this widget is
426 // redefined after a widget inherits from it
427 _childConstructors: []
428 });
429
430 basePrototype = new base();
431 // we need to make the options hash a property directly on the new instance
432 // otherwise we'll modify the options hash on the prototype that we're
433 // inheriting from
434 basePrototype.options = $.widget.extend( {}, basePrototype.options );
435 $.each( prototype, function( prop, value ) {
436 if ( $.isFunction( value ) ) {
437 prototype[ prop ] = (function() {
438 var _super = function() {
439 return base.prototype[ prop ].apply( this, arguments );
440 },
441 _superApply = function( args ) {
442 return base.prototype[ prop ].apply( this, args );
443 };
444 return function() {
445 var __super = this._super,
446 __superApply = this._superApply,
447 returnValue;
448
449 this._super = _super;
450 this._superApply = _superApply;
451
452 returnValue = value.apply( this, arguments );
453
454 this._super = __super;
455 this._superApply = __superApply;
456
457 return returnValue;
458 };
459 })();
460 }
461 });
462 constructor.prototype = $.widget.extend( basePrototype, {
463 // TODO: remove support for widgetEventPrefix
464 // always use the name + a colon as the prefix, e.g., draggable:start
465 // don't prefix for widgets that aren't DOM-based
466 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
467 }, prototype, {
468 constructor: constructor,
469 namespace: namespace,
470 widgetName: name,
471 widgetFullName: fullName
472 });
473
474 // If this widget is being redefined then we need to find all widgets that
475 // are inheriting from it and redefine all of them so that they inherit from
476 // the new version of this widget. We're essentially trying to replace one
477 // level in the prototype chain.
478 if ( existingConstructor ) {
479 $.each( existingConstructor._childConstructors, function( i, child ) {
480 var childPrototype = child.prototype;
481
482 // redefine the child widget using the same prototype that was
483 // originally used, but inherit from the new version of the base
484 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
485 });
486 // remove the list of existing child constructors from the old constructor
487 // so the old child constructors can be garbage collected
488 delete existingConstructor._childConstructors;
489 } else {
490 base._childConstructors.push( constructor );
491 }
492
493 $.widget.bridge( name, constructor );
494};
495
496$.widget.extend = function( target ) {
497 var input = slice.call( arguments, 1 ),
498 inputIndex = 0,
499 inputLength = input.length,
500 key,
501 value;
502 for ( ; inputIndex < inputLength; inputIndex++ ) {
503 for ( key in input[ inputIndex ] ) {
504 value = input[ inputIndex ][ key ];
505 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
506 // Clone objects
507 if ( $.isPlainObject( value ) ) {
508 target[ key ] = $.isPlainObject( target[ key ] ) ?
509 $.widget.extend( {}, target[ key ], value ) :
510 // Don't extend strings, arrays, etc. with objects
511 $.widget.extend( {}, value );
512 // Copy everything else by reference
513 } else {
514 target[ key ] = value;
515 }
516 }
517 }
518 }
519 return target;
520};
521
522$.widget.bridge = function( name, object ) {
523 var fullName = object.prototype.widgetFullName || name;
524 $.fn[ name ] = function( options ) {
525 var isMethodCall = typeof options === "string",
526 args = slice.call( arguments, 1 ),
527 returnValue = this;
528
529 // allow multiple hashes to be passed on init
530 options = !isMethodCall && args.length ?
531 $.widget.extend.apply( null, [ options ].concat(args) ) :
532 options;
533
534 if ( isMethodCall ) {
535 this.each(function() {
536 var methodValue,
537 instance = $.data( this, fullName );
538 if ( !instance ) {
539 return $.error( "cannot call methods on " + name + " prior to initialization; " +
540 "attempted to call method '" + options + "'" );
541 }
542 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
543 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
544 }
545 methodValue = instance[ options ].apply( instance, args );
546 if ( methodValue !== instance && methodValue !== undefined ) {
547 returnValue = methodValue && methodValue.jquery ?
548 returnValue.pushStack( methodValue.get() ) :
549 methodValue;
550 return false;
551 }
552 });
553 } else {
554 this.each(function() {
555 var instance = $.data( this, fullName );
556 if ( instance ) {
557 instance.option( options || {} )._init();
558 } else {
559 $.data( this, fullName, new object( options, this ) );
560 }
561 });
562 }
563
564 return returnValue;
565 };
566};
567
568$.Widget = function( /* options, element */ ) {};
569$.Widget._childConstructors = [];
570
571$.Widget.prototype = {
572 widgetName: "widget",
573 widgetEventPrefix: "",
574 defaultElement: "<div>",
575 options: {
576 disabled: false,
577
578 // callbacks
579 create: null
580 },
581 _createWidget: function( options, element ) {
582 element = $( element || this.defaultElement || this )[ 0 ];
583 this.element = $( element );
584 this.uuid = uuid++;
585 this.eventNamespace = "." + this.widgetName + this.uuid;
586 this.options = $.widget.extend( {},
587 this.options,
588 this._getCreateOptions(),
589 options );
590
591 this.bindings = $();
592 this.hoverable = $();
593 this.focusable = $();
594
595 if ( element !== this ) {
596 $.data( element, this.widgetFullName, this );
597 this._on( true, this.element, {
598 remove: function( event ) {
599 if ( event.target === element ) {
600 this.destroy();
601 }
602 }
603 });
604 this.document = $( element.style ?
605 // element within the document
606 element.ownerDocument :
607 // element is window or document
608 element.document || element );
609 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
610 }
611
612 this._create();
613 this._trigger( "create", null, this._getCreateEventData() );
614 this._init();
615 },
616 _getCreateOptions: $.noop,
617 _getCreateEventData: $.noop,
618 _create: $.noop,
619 _init: $.noop,
620
621 destroy: function() {
622 this._destroy();
623 // we can probably remove the unbind calls in 2.0
624 // all event bindings should go through this._on()
625 this.element
626 .unbind( this.eventNamespace )
627 // 1.9 BC for #7810
628 // TODO remove dual storage
629 .removeData( this.widgetName )
630 .removeData( this.widgetFullName )
631 // support: jquery <1.6.3
632 // http://bugs.jquery.com/ticket/9413
633 .removeData( $.camelCase( this.widgetFullName ) );
634 this.widget()
635 .unbind( this.eventNamespace )
636 .removeAttr( "aria-disabled" )
637 .removeClass(
638 this.widgetFullName + "-disabled " +
639 "ui-state-disabled" );
640
641 // clean up events and states
642 this.bindings.unbind( this.eventNamespace );
643 this.hoverable.removeClass( "ui-state-hover" );
644 this.focusable.removeClass( "ui-state-focus" );
645 },
646 _destroy: $.noop,
647
648 widget: function() {
649 return this.element;
650 },
651
652 option: function( key, value ) {
653 var options = key,
654 parts,
655 curOption,
656 i;
657
658 if ( arguments.length === 0 ) {
659 // don't return a reference to the internal hash
660 return $.widget.extend( {}, this.options );
661 }
662
663 if ( typeof key === "string" ) {
664 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
665 options = {};
666 parts = key.split( "." );
667 key = parts.shift();
668 if ( parts.length ) {
669 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
670 for ( i = 0; i < parts.length - 1; i++ ) {
671 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
672 curOption = curOption[ parts[ i ] ];
673 }
674 key = parts.pop();
675 if ( value === undefined ) {
676 return curOption[ key ] === undefined ? null : curOption[ key ];
677 }
678 curOption[ key ] = value;
679 } else {
680 if ( value === undefined ) {
681 return this.options[ key ] === undefined ? null : this.options[ key ];
682 }
683 options[ key ] = value;
684 }
685 }
686
687 this._setOptions( options );
688
689 return this;
690 },
691 _setOptions: function( options ) {
692 var key;
693
694 for ( key in options ) {
695 this._setOption( key, options[ key ] );
696 }
697
698 return this;
699 },
700 _setOption: function( key, value ) {
701 this.options[ key ] = value;
702
703 if ( key === "disabled" ) {
704 this.widget()
705 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
706 .attr( "aria-disabled", value );
707 this.hoverable.removeClass( "ui-state-hover" );
708 this.focusable.removeClass( "ui-state-focus" );
709 }
710
711 return this;
712 },
713
714 enable: function() {
715 return this._setOption( "disabled", false );
716 },
717 disable: function() {
718 return this._setOption( "disabled", true );
719 },
720
721 _on: function( suppressDisabledCheck, element, handlers ) {
722 var delegateElement,
723 instance = this;
724
725 // no suppressDisabledCheck flag, shuffle arguments
726 if ( typeof suppressDisabledCheck !== "boolean" ) {
727 handlers = element;
728 element = suppressDisabledCheck;
729 suppressDisabledCheck = false;
730 }
731
732 // no element argument, shuffle and use this.element
733 if ( !handlers ) {
734 handlers = element;
735 element = this.element;
736 delegateElement = this.widget();
737 } else {
738 // accept selectors, DOM elements
739 element = delegateElement = $( element );
740 this.bindings = this.bindings.add( element );
741 }
742
743 $.each( handlers, function( event, handler ) {
744 function handlerProxy() {
745 // allow widgets to customize the disabled handling
746 // - disabled as an array instead of boolean
747 // - disabled class as method for disabling individual parts
748 if ( !suppressDisabledCheck &&
749 ( instance.options.disabled === true ||
750 $( this ).hasClass( "ui-state-disabled" ) ) ) {
751 return;
752 }
753 return ( typeof handler === "string" ? instance[ handler ] : handler )
754 .apply( instance, arguments );
755 }
756
757 // copy the guid so direct unbinding works
758 if ( typeof handler !== "string" ) {
759 handlerProxy.guid = handler.guid =
760 handler.guid || handlerProxy.guid || $.guid++;
761 }
762
763 var match = event.match( /^(\w+)\s*(.*)$/ ),
764 eventName = match[1] + instance.eventNamespace,
765 selector = match[2];
766 if ( selector ) {
767 delegateElement.delegate( selector, eventName, handlerProxy );
768 } else {
769 element.bind( eventName, handlerProxy );
770 }
771 });
772 },
773
774 _off: function( element, eventName ) {
775 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
776 element.unbind( eventName ).undelegate( eventName );
777 },
778
779 _delay: function( handler, delay ) {
780 function handlerProxy() {
781 return ( typeof handler === "string" ? instance[ handler ] : handler )
782 .apply( instance, arguments );
783 }
784 var instance = this;
785 return setTimeout( handlerProxy, delay || 0 );
786 },
787
788 _hoverable: function( element ) {
789 this.hoverable = this.hoverable.add( element );
790 this._on( element, {
791 mouseenter: function( event ) {
792 $( event.currentTarget ).addClass( "ui-state-hover" );
793 },
794 mouseleave: function( event ) {
795 $( event.currentTarget ).removeClass( "ui-state-hover" );
796 }
797 });
798 },
799
800 _focusable: function( element ) {
801 this.focusable = this.focusable.add( element );
802 this._on( element, {
803 focusin: function( event ) {
804 $( event.currentTarget ).addClass( "ui-state-focus" );
805 },
806 focusout: function( event ) {
807 $( event.currentTarget ).removeClass( "ui-state-focus" );
808 }
809 });
810 },
811
812 _trigger: function( type, event, data ) {
813 var prop, orig,
814 callback = this.options[ type ];
815
816 data = data || {};
817 event = $.Event( event );
818 event.type = ( type === this.widgetEventPrefix ?
819 type :
820 this.widgetEventPrefix + type ).toLowerCase();
821 // the original event may come from any element
822 // so we need to reset the target on the new event
823 event.target = this.element[ 0 ];
824
825 // copy original event properties over to the new event
826 orig = event.originalEvent;
827 if ( orig ) {
828 for ( prop in orig ) {
829 if ( !( prop in event ) ) {
830 event[ prop ] = orig[ prop ];
831 }
832 }
833 }
834
835 this.element.trigger( event, data );
836 return !( $.isFunction( callback ) &&
837 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
838 event.isDefaultPrevented() );
839 }
840};
841
842$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
843 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
844 if ( typeof options === "string" ) {
845 options = { effect: options };
846 }
847 var hasOptions,
848 effectName = !options ?
849 method :
850 options === true || typeof options === "number" ?
851 defaultEffect :
852 options.effect || defaultEffect;
853 options = options || {};
854 if ( typeof options === "number" ) {
855 options = { duration: options };
856 }
857 hasOptions = !$.isEmptyObject( options );
858 options.complete = callback;
859 if ( options.delay ) {
860 element.delay( options.delay );
861 }
862 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
863 element[ method ]( options );
864 } else if ( effectName !== method && element[ effectName ] ) {
865 element[ effectName ]( options.duration, options.easing, callback );
866 } else {
867 element.queue(function( next ) {
868 $( this )[ method ]();
869 if ( callback ) {
870 callback.call( element[ 0 ] );
871 }
872 next();
873 });
874 }
875 };
876});
877
878})( jQuery );
879
880(function( $, undefined ) {
881
882$.widget( "mobile.widget", {
883 // decorate the parent _createWidget to trigger `widgetinit` for users
884 // who wish to do post post `widgetcreate` alterations/additions
885 //
886 // TODO create a pull request for jquery ui to trigger this event
887 // in the original _createWidget
888 _createWidget: function() {
889 $.Widget.prototype._createWidget.apply( this, arguments );
890 this._trigger( 'init' );
891 },
892
893 _getCreateOptions: function() {
894
895 var elem = this.element,
896 options = {};
897
898 $.each( this.options, function( option ) {
899
900 var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
901 return "-" + c.toLowerCase();
902 })
903 );
904
905 if ( value !== undefined ) {
906 options[ option ] = value;
907 }
908 });
909
910 return options;
911 },
912
913 enhanceWithin: function( target, useKeepNative ) {
914 this.enhance( $( this.options.initSelector, $( target )), useKeepNative );
915 },
916
917 enhance: function( targets, useKeepNative ) {
918 var page, keepNative, $widgetElements = $( targets ), self = this;
919
920 // if ignoreContentEnabled is set to true the framework should
921 // only enhance the selected elements when they do NOT have a
922 // parent with the data-namespace-ignore attribute
923 $widgetElements = $.mobile.enhanceable( $widgetElements );
924
925 if ( useKeepNative && $widgetElements.length ) {
926 // TODO remove dependency on the page widget for the keepNative.
927 // Currently the keepNative value is defined on the page prototype so
928 // the method is as well
929 page = $.mobile.closestPageData( $widgetElements );
930 keepNative = ( page && page.keepNativeSelector()) || "";
931
932 $widgetElements = $widgetElements.not( keepNative );
933 }
934
935 $widgetElements[ this.widgetName ]();
936 },
937
938 raise: function( msg ) {
939 throw "Widget [" + this.widgetName + "]: " + msg;
940 }
941});
942
943})( jQuery );
944
945
946(function( $, window ) {
947 // DEPRECATED
948 // NOTE global mobile object settings
949 $.extend( $.mobile, {
950 // DEPRECATED Should the text be visble in the loading message?
951 loadingMessageTextVisible: undefined,
952
953 // DEPRECATED When the text is visible, what theme does the loading box use?
954 loadingMessageTheme: undefined,
955
956 // DEPRECATED default message setting
957 loadingMessage: undefined,
958
959 // DEPRECATED
960 // Turn on/off page loading message. Theme doubles as an object argument
961 // with the following shape: { theme: '', text: '', html: '', textVisible: '' }
962 // NOTE that the $.mobile.loading* settings and params past the first are deprecated
963 showPageLoadingMsg: function( theme, msgText, textonly ) {
964 $.mobile.loading( 'show', theme, msgText, textonly );
965 },
966
967 // DEPRECATED
968 hidePageLoadingMsg: function() {
969 $.mobile.loading( 'hide' );
970 },
971
972 loading: function() {
973 this.loaderWidget.loader.apply( this.loaderWidget, arguments );
974 }
975 });
976
977 // TODO move loader class down into the widget settings
978 var loaderClass = "ui-loader", $html = $( "html" ), $window = $.mobile.window;
979
980 $.widget( "mobile.loader", {
981 // NOTE if the global config settings are defined they will override these
982 // options
983 options: {
984 // the theme for the loading message
985 theme: "a",
986
987 // whether the text in the loading message is shown
988 textVisible: false,
989
990 // custom html for the inner content of the loading message
991 html: "",
992
993 // the text to be displayed when the popup is shown
994 text: "loading"
995 },
996
997 defaultHtml: "<div class='" + loaderClass + "'>" +
998 "<span class='ui-icon ui-icon-loading'></span>" +
999 "<h1></h1>" +
1000 "</div>",
1001
1002 // For non-fixed supportin browsers. Position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
1003 fakeFixLoader: function() {
1004 var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
1005
1006 this.element
1007 .css({
1008 top: $.support.scrollTop && $window.scrollTop() + $window.height() / 2 ||
1009 activeBtn.length && activeBtn.offset().top || 100
1010 });
1011 },
1012
1013 // check position of loader to see if it appears to be "fixed" to center
1014 // if not, use abs positioning
1015 checkLoaderPosition: function() {
1016 var offset = this.element.offset(),
1017 scrollTop = $window.scrollTop(),
1018 screenHeight = $.mobile.getScreenHeight();
1019
1020 if ( offset.top < scrollTop || ( offset.top - scrollTop ) > screenHeight ) {
1021 this.element.addClass( "ui-loader-fakefix" );
1022 this.fakeFixLoader();
1023 $window
1024 .unbind( "scroll", this.checkLoaderPosition )
1025 .bind( "scroll", $.proxy( this.fakeFixLoader, this ) );
1026 }
1027 },
1028
1029 resetHtml: function() {
1030 this.element.html( $( this.defaultHtml ).html() );
1031 },
1032
1033 // Turn on/off page loading message. Theme doubles as an object argument
1034 // with the following shape: { theme: '', text: '', html: '', textVisible: '' }
1035 // NOTE that the $.mobile.loading* settings and params past the first are deprecated
1036 // TODO sweet jesus we need to break some of this out
1037 show: function( theme, msgText, textonly ) {
1038 var textVisible, message, $header, loadSettings;
1039
1040 this.resetHtml();
1041
1042 // use the prototype options so that people can set them globally at
1043 // mobile init. Consistency, it's what's for dinner
1044 if ( $.type(theme) === "object" ) {
1045 loadSettings = $.extend( {}, this.options, theme );
1046
1047 // prefer object property from the param then the old theme setting
1048 theme = loadSettings.theme || $.mobile.loadingMessageTheme;
1049 } else {
1050 loadSettings = this.options;
1051
1052 // here we prefer the them value passed as a string argument, then
1053 // we prefer the global option because we can't use undefined default
1054 // prototype options, then the prototype option
1055 theme = theme || $.mobile.loadingMessageTheme || loadSettings.theme;
1056 }
1057
1058 // set the message text, prefer the param, then the settings object
1059 // then loading message
1060 message = msgText || $.mobile.loadingMessage || loadSettings.text;
1061
1062 // prepare the dom
1063 $html.addClass( "ui-loading" );
1064
1065 if ( $.mobile.loadingMessage !== false || loadSettings.html ) {
1066 // boolean values require a bit more work :P, supports object properties
1067 // and old settings
1068 if ( $.mobile.loadingMessageTextVisible !== undefined ) {
1069 textVisible = $.mobile.loadingMessageTextVisible;
1070 } else {
1071 textVisible = loadSettings.textVisible;
1072 }
1073
1074 // add the proper css given the options (theme, text, etc)
1075 // Force text visibility if the second argument was supplied, or
1076 // if the text was explicitly set in the object args
1077 this.element.attr("class", loaderClass +
1078 " ui-corner-all ui-body-" + theme +
1079 " ui-loader-" + ( textVisible || msgText || theme.text ? "verbose" : "default" ) +
1080 ( loadSettings.textonly || textonly ? " ui-loader-textonly" : "" ) );
1081
1082 // TODO verify that jquery.fn.html is ok to use in both cases here
1083 // this might be overly defensive in preventing unknowing xss
1084 // if the html attribute is defined on the loading settings, use that
1085 // otherwise use the fallbacks from above
1086 if ( loadSettings.html ) {
1087 this.element.html( loadSettings.html );
1088 } else {
1089 this.element.find( "h1" ).text( message );
1090 }
1091
1092 // attach the loader to the DOM
1093 this.element.appendTo( $.mobile.pageContainer );
1094
1095 // check that the loader is visible
1096 this.checkLoaderPosition();
1097
1098 // on scroll check the loader position
1099 $window.bind( "scroll", $.proxy( this.checkLoaderPosition, this ) );
1100 }
1101 },
1102
1103 hide: function() {
1104 $html.removeClass( "ui-loading" );
1105
1106 if ( $.mobile.loadingMessage ) {
1107 this.element.removeClass( "ui-loader-fakefix" );
1108 }
1109
1110 $.mobile.window.unbind( "scroll", this.fakeFixLoader );
1111 $.mobile.window.unbind( "scroll", this.checkLoaderPosition );
1112 }
1113 });
1114
1115 $window.bind( 'pagecontainercreate', function() {
1116 $.mobile.loaderWidget = $.mobile.loaderWidget || $( $.mobile.loader.prototype.defaultHtml ).loader();
1117 });
1118})(jQuery, this);
1119
1120
1121// Script: jQuery hashchange event
1122//
1123// *Version: 1.3, Last updated: 7/21/2010*
1124//
1125// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
1126// GitHub - http://github.com/cowboy/jquery-hashchange/
1127// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
1128// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
1129//
1130// About: License
1131//
1132// Copyright (c) 2010 "Cowboy" Ben Alman,
1133// Dual licensed under the MIT and GPL licenses.
1134// http://benalman.com/about/license/
1135//
1136// About: Examples
1137//
1138// These working examples, complete with fully commented code, illustrate a few
1139// ways in which this plugin can be used.
1140//
1141// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
1142// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
1143//
1144// About: Support and Testing
1145//
1146// Information about what version or versions of jQuery this plugin has been
1147// tested with, what browsers it has been tested in, and where the unit tests
1148// reside (so you can test it yourself).
1149//
1150// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
1151// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
1152// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
1153// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
1154//
1155// About: Known issues
1156//
1157// While this jQuery hashchange event implementation is quite stable and
1158// robust, there are a few unfortunate browser bugs surrounding expected
1159// hashchange event-based behaviors, independent of any JavaScript
1160// window.onhashchange abstraction. See the following examples for more
1161// information:
1162//
1163// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
1164// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
1165// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
1166// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
1167//
1168// Also note that should a browser natively support the window.onhashchange
1169// event, but not report that it does, the fallback polling loop will be used.
1170//
1171// About: Release History
1172//
1173// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
1174// "removable" for mobile-only development. Added IE6/7 document.title
1175// support. Attempted to make Iframe as hidden as possible by using
1176// techniques from http://www.paciellogroup.com/blog/?p=604. Added
1177// support for the "shortcut" format $(window).hashchange( fn ) and
1178// $(window).hashchange() like jQuery provides for built-in events.
1179// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
1180// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
1181// and <jQuery.fn.hashchange.src> properties plus document-domain.html
1182// file to address access denied issues when setting document.domain in
1183// IE6/7.
1184// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
1185// from a page on another domain would cause an error in Safari 4. Also,
1186// IE6/7 Iframe is now inserted after the body (this actually works),
1187// which prevents the page from scrolling when the event is first bound.
1188// Event can also now be bound before DOM ready, but it won't be usable
1189// before then in IE6/7.
1190// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
1191// where browser version is incorrectly reported as 8.0, despite
1192// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
1193// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
1194// window.onhashchange functionality into a separate plugin for users
1195// who want just the basic event & back button support, without all the
1196// extra awesomeness that BBQ provides. This plugin will be included as
1197// part of jQuery BBQ, but also be available separately.
1198
1199(function( $, window, undefined ) {
1200 // Reused string.
1201 var str_hashchange = 'hashchange',
1202
1203 // Method / object references.
1204 doc = document,
1205 fake_onhashchange,
1206 special = $.event.special,
1207
1208 // Does the browser support window.onhashchange? Note that IE8 running in
1209 // IE7 compatibility mode reports true for 'onhashchange' in window, even
1210 // though the event isn't supported, so also test document.documentMode.
1211 doc_mode = doc.documentMode,
1212 supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
1213
1214 // Get location.hash (or what you'd expect location.hash to be) sans any
1215 // leading #. Thanks for making this necessary, Firefox!
1216 function get_fragment( url ) {
1217 url = url || location.href;
1218 return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
1219 };
1220
1221 // Method: jQuery.fn.hashchange
1222 //
1223 // Bind a handler to the window.onhashchange event or trigger all bound
1224 // window.onhashchange event handlers. This behavior is consistent with
1225 // jQuery's built-in event handlers.
1226 //
1227 // Usage:
1228 //
1229 // > jQuery(window).hashchange( [ handler ] );
1230 //
1231 // Arguments:
1232 //
1233 // handler - (Function) Optional handler to be bound to the hashchange
1234 // event. This is a "shortcut" for the more verbose form:
1235 // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
1236 // all bound window.onhashchange event handlers will be triggered. This
1237 // is a shortcut for the more verbose
1238 // jQuery(window).trigger( 'hashchange' ). These forms are described in
1239 // the <hashchange event> section.
1240 //
1241 // Returns:
1242 //
1243 // (jQuery) The initial jQuery collection of elements.
1244
1245 // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
1246 // $(elem).hashchange() for triggering, like jQuery does for built-in events.
1247 $.fn[ str_hashchange ] = function( fn ) {
1248 return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
1249 };
1250
1251 // Property: jQuery.fn.hashchange.delay
1252 //
1253 // The numeric interval (in milliseconds) at which the <hashchange event>
1254 // polling loop executes. Defaults to 50.
1255
1256 // Property: jQuery.fn.hashchange.domain
1257 //
1258 // If you're setting document.domain in your JavaScript, and you want hash
1259 // history to work in IE6/7, not only must this property be set, but you must
1260 // also set document.domain BEFORE jQuery is loaded into the page. This
1261 // property is only applicable if you are supporting IE6/7 (or IE8 operating
1262 // in "IE7 compatibility" mode).
1263 //
1264 // In addition, the <jQuery.fn.hashchange.src> property must be set to the
1265 // path of the included "document-domain.html" file, which can be renamed or
1266 // modified if necessary (note that the document.domain specified must be the
1267 // same in both your main JavaScript as well as in this file).
1268 //
1269 // Usage:
1270 //
1271 // jQuery.fn.hashchange.domain = document.domain;
1272
1273 // Property: jQuery.fn.hashchange.src
1274 //
1275 // If, for some reason, you need to specify an Iframe src file (for example,
1276 // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
1277 // do so using this property. Note that when using this property, history
1278 // won't be recorded in IE6/7 until the Iframe src file loads. This property
1279 // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
1280 // compatibility" mode).
1281 //
1282 // Usage:
1283 //
1284 // jQuery.fn.hashchange.src = 'path/to/file.html';
1285
1286 $.fn[ str_hashchange ].delay = 50;
1287 /*
1288 $.fn[ str_hashchange ].domain = null;
1289 $.fn[ str_hashchange ].src = null;
1290 */
1291
1292 // Event: hashchange event
1293 //
1294 // Fired when location.hash changes. In browsers that support it, the native
1295 // HTML5 window.onhashchange event is used, otherwise a polling loop is
1296 // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
1297 // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
1298 // compatibility" mode), a hidden Iframe is created to allow the back button
1299 // and hash-based history to work.
1300 //
1301 // Usage as described in <jQuery.fn.hashchange>:
1302 //
1303 // > // Bind an event handler.
1304 // > jQuery(window).hashchange( function(e) {
1305 // > var hash = location.hash;
1306 // > ...
1307 // > });
1308 // >
1309 // > // Manually trigger the event handler.
1310 // > jQuery(window).hashchange();
1311 //
1312 // A more verbose usage that allows for event namespacing:
1313 //
1314 // > // Bind an event handler.
1315 // > jQuery(window).bind( 'hashchange', function(e) {
1316 // > var hash = location.hash;
1317 // > ...
1318 // > });
1319 // >
1320 // > // Manually trigger the event handler.
1321 // > jQuery(window).trigger( 'hashchange' );
1322 //
1323 // Additional Notes:
1324 //
1325 // * The polling loop and Iframe are not created until at least one handler
1326 // is actually bound to the 'hashchange' event.
1327 // * If you need the bound handler(s) to execute immediately, in cases where
1328 // a location.hash exists on page load, via bookmark or page refresh for
1329 // example, use jQuery(window).hashchange() or the more verbose
1330 // jQuery(window).trigger( 'hashchange' ).
1331 // * The event can be bound before DOM ready, but since it won't be usable
1332 // before then in IE6/7 (due to the necessary Iframe), recommended usage is
1333 // to bind it inside a DOM ready handler.
1334
1335 // Override existing $.event.special.hashchange methods (allowing this plugin
1336 // to be defined after jQuery BBQ in BBQ's source code).
1337 special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
1338
1339 // Called only when the first 'hashchange' event is bound to window.
1340 setup: function() {
1341 // If window.onhashchange is supported natively, there's nothing to do..
1342 if ( supports_onhashchange ) { return false; }
1343
1344 // Otherwise, we need to create our own. And we don't want to call this
1345 // until the user binds to the event, just in case they never do, since it
1346 // will create a polling loop and possibly even a hidden Iframe.
1347 $( fake_onhashchange.start );
1348 },
1349
1350 // Called only when the last 'hashchange' event is unbound from window.
1351 teardown: function() {
1352 // If window.onhashchange is supported natively, there's nothing to do..
1353 if ( supports_onhashchange ) { return false; }
1354
1355 // Otherwise, we need to stop ours (if possible).
1356 $( fake_onhashchange.stop );
1357 }
1358
1359 });
1360
1361 // fake_onhashchange does all the work of triggering the window.onhashchange
1362 // event for browsers that don't natively support it, including creating a
1363 // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1364 // Iframe to enable back and forward.
1365 fake_onhashchange = (function() {
1366 var self = {},
1367 timeout_id,
1368
1369 // Remember the initial hash so it doesn't get triggered immediately.
1370 last_hash = get_fragment(),
1371
1372 fn_retval = function( val ) { return val; },
1373 history_set = fn_retval,
1374 history_get = fn_retval;
1375
1376 // Start the polling loop.
1377 self.start = function() {
1378 timeout_id || poll();
1379 };
1380
1381 // Stop the polling loop.
1382 self.stop = function() {
1383 timeout_id && clearTimeout( timeout_id );
1384 timeout_id = undefined;
1385 };
1386
1387 // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1388 // if location.hash has changed, and triggers the 'hashchange' event on
1389 // window when necessary.
1390 function poll() {
1391 var hash = get_fragment(),
1392 history_hash = history_get( last_hash );
1393
1394 if ( hash !== last_hash ) {
1395 history_set( last_hash = hash, history_hash );
1396
1397 $(window).trigger( str_hashchange );
1398
1399 } else if ( history_hash !== last_hash ) {
1400 location.href = location.href.replace( /#.*/, '' ) + history_hash;
1401 }
1402
1403 timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
1404 };
1405
1406 // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1407 // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
1408 // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1409 window.attachEvent && !window.addEventListener && !supports_onhashchange && (function() {
1410 // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
1411 // when running in "IE7 compatibility" mode.
1412
1413 var iframe,
1414 iframe_src;
1415
1416 // When the event is bound and polling starts in IE 6/7, create a hidden
1417 // Iframe for history handling.
1418 self.start = function() {
1419 if ( !iframe ) {
1420 iframe_src = $.fn[ str_hashchange ].src;
1421 iframe_src = iframe_src && iframe_src + get_fragment();
1422
1423 // Create hidden Iframe. Attempt to make Iframe as hidden as possible
1424 // by using techniques from http://www.paciellogroup.com/blog/?p=604.
1425 iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
1426
1427 // When Iframe has completely loaded, initialize the history and
1428 // start polling.
1429 .one( 'load', function() {
1430 iframe_src || history_set( get_fragment() );
1431 poll();
1432 })
1433
1434 // Load Iframe src if specified, otherwise nothing.
1435 .attr( 'src', iframe_src || 'javascript:0' )
1436
1437 // Append Iframe after the end of the body to prevent unnecessary
1438 // initial page scrolling (yes, this works).
1439 .insertAfter( 'body' )[0].contentWindow;
1440
1441 // Whenever `document.title` changes, update the Iframe's title to
1442 // prettify the back/next history menu entries. Since IE sometimes
1443 // errors with "Unspecified error" the very first time this is set
1444 // (yes, very useful) wrap this with a try/catch block.
1445 doc.onpropertychange = function() {
1446 try {
1447 if ( event.propertyName === 'title' ) {
1448 iframe.document.title = doc.title;
1449 }
1450 } catch(e) {}
1451 };
1452
1453 }
1454 };
1455
1456 // Override the "stop" method since an IE6/7 Iframe was created. Even
1457 // if there are no longer any bound event handlers, the polling loop
1458 // is still necessary for back/next to work at all!
1459 self.stop = fn_retval;
1460
1461 // Get history by looking at the hidden Iframe's location.hash.
1462 history_get = function() {
1463 return get_fragment( iframe.location.href );
1464 };
1465
1466 // Set a new history item by opening and then closing the Iframe
1467 // document, *then* setting its location.hash. If document.domain has
1468 // been set, update that as well.
1469 history_set = function( hash, history_hash ) {
1470 var iframe_doc = iframe.document,
1471 domain = $.fn[ str_hashchange ].domain;
1472
1473 if ( hash !== history_hash ) {
1474 // Update Iframe with any initial `document.title` that might be set.
1475 iframe_doc.title = doc.title;
1476
1477 // Opening the Iframe's document after it has been closed is what
1478 // actually adds a history entry.
1479 iframe_doc.open();
1480
1481 // Set document.domain for the Iframe document as well, if necessary.
1482 domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
1483
1484 iframe_doc.close();
1485
1486 // Update the Iframe's hash, for great justice.
1487 iframe.location.hash = hash;
1488 }
1489 };
1490
1491 })();
1492 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1493 // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
1494 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1495
1496 return self;
1497 })();
1498
1499})(jQuery,this);
1500
1501(function( $, undefined ) {
1502
1503 /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
1504 window.matchMedia = window.matchMedia || (function( doc, undefined ) {
1505
1506
1507
1508 var bool,
1509 docElem = doc.documentElement,
1510 refNode = docElem.firstElementChild || docElem.firstChild,
1511 // fakeBody required for <FF4 when executed in <head>
1512 fakeBody = doc.createElement( "body" ),
1513 div = doc.createElement( "div" );
1514
1515 div.id = "mq-test-1";
1516 div.style.cssText = "position:absolute;top:-100em";
1517 fakeBody.style.background = "none";
1518 fakeBody.appendChild(div);
1519
1520 return function(q){
1521
1522 div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
1523
1524 docElem.insertBefore( fakeBody, refNode );
1525 bool = div.offsetWidth === 42;
1526 docElem.removeChild( fakeBody );
1527
1528 return {
1529 matches: bool,
1530 media: q
1531 };
1532
1533 };
1534
1535 }( document ));
1536
1537 // $.mobile.media uses matchMedia to return a boolean.
1538 $.mobile.media = function( q ) {
1539 return window.matchMedia( q ).matches;
1540 };
1541
1542})(jQuery);
1543
1544 (function( $, undefined ) {
1545 var support = {
1546 touch: "ontouchend" in document
1547 };
1548
1549 $.mobile.support = $.mobile.support || {};
1550 $.extend( $.support, support );
1551 $.extend( $.mobile.support, support );
1552 }( jQuery ));
1553
1554 (function( $, undefined ) {
1555 $.extend( $.support, {
1556 orientation: "orientation" in window && "onorientationchange" in window
1557 });
1558 }( jQuery ));
1559
1560(function( $, undefined ) {
1561
1562// thx Modernizr
1563function propExists( prop ) {
1564 var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
1565 props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );
1566
1567 for ( var v in props ) {
1568 if ( fbCSS[ props[ v ] ] !== undefined ) {
1569 return true;
1570 }
1571 }
1572}
1573
1574var fakeBody = $( "<body>" ).prependTo( "html" ),
1575 fbCSS = fakeBody[ 0 ].style,
1576 vendors = [ "Webkit", "Moz", "O" ],
1577 webos = "palmGetResource" in window, //only used to rule out scrollTop
1578 opera = window.opera,
1579 operamini = window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]",
1580 bb = window.blackberry && !propExists( "-webkit-transform" ); //only used to rule out box shadow, as it's filled opaque on BB 5 and lower
1581
1582
1583function validStyle( prop, value, check_vend ) {
1584 var div = document.createElement( 'div' ),
1585 uc = function( txt ) {
1586 return txt.charAt( 0 ).toUpperCase() + txt.substr( 1 );
1587 },
1588 vend_pref = function( vend ) {
1589 if( vend === "" ) {
1590 return "";
1591 } else {
1592 return "-" + vend.charAt( 0 ).toLowerCase() + vend.substr( 1 ) + "-";
1593 }
1594 },
1595 check_style = function( vend ) {
1596 var vend_prop = vend_pref( vend ) + prop + ": " + value + ";",
1597 uc_vend = uc( vend ),
1598 propStyle = uc_vend + ( uc_vend === "" ? prop : uc( prop ) );
1599
1600 div.setAttribute( "style", vend_prop );
1601
1602 if ( !!div.style[ propStyle ] ) {
1603 ret = true;
1604 }
1605 },
1606 check_vends = check_vend ? check_vend : vendors,
1607 ret;
1608
1609 for( var i = 0; i < check_vends.length; i++ ) {
1610 check_style( check_vends[i] );
1611 }
1612 return !!ret;
1613}
1614
1615function transform3dTest() {
1616 var mqProp = "transform-3d",
1617 // Because the `translate3d` test below throws false positives in Android:
1618 ret = $.mobile.media( "(-" + vendors.join( "-" + mqProp + "),(-" ) + "-" + mqProp + "),(" + mqProp + ")" );
1619
1620 if( ret ) {
1621 return !!ret;
1622 }
1623
1624 var el = document.createElement( "div" ),
1625 transforms = {
1626 // We’re omitting Opera for the time being; MS uses unprefixed.
1627 'MozTransform':'-moz-transform',
1628 'transform':'transform'
1629 };
1630
1631 fakeBody.append( el );
1632
1633 for ( var t in transforms ) {
1634 if( el.style[ t ] !== undefined ){
1635 el.style[ t ] = 'translate3d( 100px, 1px, 1px )';
1636 ret = window.getComputedStyle( el ).getPropertyValue( transforms[ t ] );
1637 }
1638 }
1639 return ( !!ret && ret !== "none" );
1640}
1641
1642// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
1643function baseTagTest() {
1644 var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
1645 base = $( "head base" ),
1646 fauxEle = null,
1647 href = "",
1648 link, rebase;
1649
1650 if ( !base.length ) {
1651 base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
1652 } else {
1653 href = base.attr( "href" );
1654 }
1655
1656 link = $( "<a href='testurl' />" ).prependTo( fakeBody );
1657 rebase = link[ 0 ].href;
1658 base[ 0 ].href = href || location.pathname;
1659
1660 if ( fauxEle ) {
1661 fauxEle.remove();
1662 }
1663 return rebase.indexOf( fauxBase ) === 0;
1664}
1665
1666// Thanks Modernizr
1667function cssPointerEventsTest() {
1668 var element = document.createElement( 'x' ),
1669 documentElement = document.documentElement,
1670 getComputedStyle = window.getComputedStyle,
1671 supports;
1672
1673 if ( !( 'pointerEvents' in element.style ) ) {
1674 return false;
1675 }
1676
1677 element.style.pointerEvents = 'auto';
1678 element.style.pointerEvents = 'x';
1679 documentElement.appendChild( element );
1680 supports = getComputedStyle &&
1681 getComputedStyle( element, '' ).pointerEvents === 'auto';
1682 documentElement.removeChild( element );
1683 return !!supports;
1684}
1685
1686function boundingRect() {
1687 var div = document.createElement( "div" );
1688 return typeof div.getBoundingClientRect !== "undefined";
1689}
1690
1691// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
1692// allows for inclusion of IE 6+, including Windows Mobile 7
1693$.extend( $.mobile, { browser: {} } );
1694$.mobile.browser.oldIE = (function() {
1695 var v = 3,
1696 div = document.createElement( "div" ),
1697 a = div.all || [];
1698
1699 do {
1700 div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->";
1701 } while( a[0] );
1702
1703 return v > 4 ? v : !v;
1704})();
1705
1706function fixedPosition() {
1707 var w = window,
1708 ua = navigator.userAgent,
1709 platform = navigator.platform,
1710 // Rendering engine is Webkit, and capture major version
1711 wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
1712 wkversion = !!wkmatch && wkmatch[ 1 ],
1713 ffmatch = ua.match( /Fennec\/([0-9]+)/ ),
1714 ffversion = !!ffmatch && ffmatch[ 1 ],
1715 operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ),
1716 omversion = !!operammobilematch && operammobilematch[ 1 ];
1717
1718 if(
1719 // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
1720 ( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 ) ||
1721 // Opera Mini
1722 ( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" ) ||
1723 ( operammobilematch && omversion < 7458 ) ||
1724 //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
1725 ( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 ) ||
1726 // Firefox Mobile before 6.0 -
1727 ( ffversion && ffversion < 6 ) ||
1728 // WebOS less than 3
1729 ( "palmGetResource" in window && wkversion && wkversion < 534 ) ||
1730 // MeeGo
1731 ( ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1 ) ) {
1732 return false;
1733 }
1734
1735 return true;
1736}
1737
1738$.extend( $.support, {
1739 cssTransitions: "WebKitTransitionEvent" in window ||
1740 validStyle( 'transition', 'height 100ms linear', [ "Webkit", "Moz", "" ] ) &&
1741 !$.mobile.browser.oldIE && !opera,
1742
1743 // Note, Chrome for iOS has an extremely quirky implementation of popstate.
1744 // We've chosen to take the shortest path to a bug fix here for issue #5426
1745 // See the following link for information about the regex chosen
1746 // https://developers.google.com/chrome/mobile/docs/user-agent#chrome_for_ios_user-agent
1747 pushState: "pushState" in history &&
1748 "replaceState" in history &&
1749 // When running inside a FF iframe, calling replaceState causes an error
1750 !( window.navigator.userAgent.indexOf( "Firefox" ) >= 0 && window.top !== window ) &&
1751 ( window.navigator.userAgent.search(/CriOS/) === -1 ),
1752
1753 mediaquery: $.mobile.media( "only all" ),
1754 cssPseudoElement: !!propExists( "content" ),
1755 touchOverflow: !!propExists( "overflowScrolling" ),
1756 cssTransform3d: transform3dTest(),
1757 boxShadow: !!propExists( "boxShadow" ) && !bb,
1758 fixedPosition: fixedPosition(),
1759 scrollTop: ("pageXOffset" in window ||
1760 "scrollTop" in document.documentElement ||
1761 "scrollTop" in fakeBody[ 0 ]) && !webos && !operamini,
1762
1763 dynamicBaseTag: baseTagTest(),
1764 cssPointerEvents: cssPointerEventsTest(),
1765 boundingRect: boundingRect()
1766});
1767
1768fakeBody.remove();
1769
1770
1771// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
1772// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
1773// Note: This detection below is used as a last resort.
1774// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
1775var nokiaLTE7_3 = (function() {
1776
1777 var ua = window.navigator.userAgent;
1778
1779 //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
1780 return ua.indexOf( "Nokia" ) > -1 &&
1781 ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
1782 ua.indexOf( "AppleWebKit" ) > -1 &&
1783 ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
1784})();
1785
1786// Support conditions that must be met in order to proceed
1787// default enhanced qualifications are media query support OR IE 7+
1788
1789$.mobile.gradeA = function() {
1790 return ( $.support.mediaquery || $.mobile.browser.oldIE && $.mobile.browser.oldIE >= 7 ) && ( $.support.boundingRect || $.fn.jquery.match(/1\.[0-7+]\.[0-9+]?/) !== null );
1791};
1792
1793$.mobile.ajaxBlacklist =
1794 // BlackBerry browsers, pre-webkit
1795 window.blackberry && !window.WebKitPoint ||
1796 // Opera Mini
1797 operamini ||
1798 // Symbian webkits pre 7.3
1799 nokiaLTE7_3;
1800
1801// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
1802// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
1803// This simply reappends the CSS in place, which for some reason makes it apply
1804if ( nokiaLTE7_3 ) {
1805 $(function() {
1806 $( "head link[rel='stylesheet']" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
1807 });
1808}
1809
1810// For ruling out shadows via css
1811if ( !$.support.boxShadow ) {
1812 $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" );
1813}
1814
1815})( jQuery );
1816
1817
1818(function( $, undefined ) {
1819 var $win = $.mobile.window, self, history;
1820
1821 $.event.special.navigate = self = {
1822 bound: false,
1823
1824 pushStateEnabled: true,
1825
1826 originalEventName: undefined,
1827
1828 // If pushstate support is present and push state support is defined to
1829 // be true on the mobile namespace.
1830 isPushStateEnabled: function() {
1831 return $.support.pushState &&
1832 $.mobile.pushStateEnabled === true &&
1833 this.isHashChangeEnabled();
1834 },
1835
1836 // !! assumes mobile namespace is present
1837 isHashChangeEnabled: function() {
1838 return $.mobile.hashListeningEnabled === true;
1839 },
1840
1841 // TODO a lot of duplication between popstate and hashchange
1842 popstate: function( event ) {
1843 var newEvent = new $.Event( "navigate" ),
1844 beforeNavigate = new $.Event( "beforenavigate" ),
1845 state = event.originalEvent.state || {},
1846 href = location.href;
1847
1848 $win.trigger( beforeNavigate );
1849
1850 if( beforeNavigate.isDefaultPrevented() ){
1851 return;
1852 }
1853
1854 if( event.historyState ){
1855 $.extend(state, event.historyState);
1856 }
1857
1858 // Make sure the original event is tracked for the end
1859 // user to inspect incase they want to do something special
1860 newEvent.originalEvent = event;
1861
1862 // NOTE we let the current stack unwind because any assignment to
1863 // location.hash will stop the world and run this event handler. By
1864 // doing this we create a similar behavior to hashchange on hash
1865 // assignment
1866 setTimeout(function() {
1867 $win.trigger( newEvent, {
1868 state: state
1869 });
1870 }, 0);
1871 },
1872
1873 hashchange: function( event, data ) {
1874 var newEvent = new $.Event( "navigate" ),
1875 beforeNavigate = new $.Event( "beforenavigate" );
1876
1877 $win.trigger( beforeNavigate );
1878
1879 if( beforeNavigate.isDefaultPrevented() ){
1880 return;
1881 }
1882
1883 // Make sure the original event is tracked for the end
1884 // user to inspect incase they want to do something special
1885 newEvent.originalEvent = event;
1886
1887 // Trigger the hashchange with state provided by the user
1888 // that altered the hash
1889 $win.trigger( newEvent, {
1890 // Users that want to fully normalize the two events
1891 // will need to do history management down the stack and
1892 // add the state to the event before this binding is fired
1893 // TODO consider allowing for the explicit addition of callbacks
1894 // to be fired before this value is set to avoid event timing issues
1895 state: event.hashchangeState || {}
1896 });
1897 },
1898
1899 // TODO We really only want to set this up once
1900 // but I'm not clear if there's a beter way to achieve
1901 // this with the jQuery special event structure
1902 setup: function( data, namespaces ) {
1903 if( self.bound ) {
1904 return;
1905 }
1906
1907 self.bound = true;
1908
1909 if( self.isPushStateEnabled() ) {
1910 self.originalEventName = "popstate";
1911 $win.bind( "popstate.navigate", self.popstate );
1912 } else if ( self.isHashChangeEnabled() ){
1913 self.originalEventName = "hashchange";
1914 $win.bind( "hashchange.navigate", self.hashchange );
1915 }
1916 }
1917 };
1918})( jQuery );
1919
1920
1921
1922(function( $, undefined ) {
1923 var path, documentBase, $base, dialogHashKey = "&ui-state=dialog";
1924
1925 $.mobile.path = path = {
1926 uiStateKey: "&ui-state",
1927
1928 // This scary looking regular expression parses an absolute URL or its relative
1929 // variants (protocol, site, document, query, and hash), into the various
1930 // components (protocol, host, path, query, fragment, etc that make up the
1931 // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
1932 // or String.match, it parses the URL into a results array that looks like this:
1933 //
1934 // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
1935 // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
1936 // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
1937 // [3]: http://jblas:password@mycompany.com:8080
1938 // [4]: http:
1939 // [5]: //
1940 // [6]: jblas:password@mycompany.com:8080
1941 // [7]: jblas:password
1942 // [8]: jblas
1943 // [9]: password
1944 // [10]: mycompany.com:8080
1945 // [11]: mycompany.com
1946 // [12]: 8080
1947 // [13]: /mail/inbox
1948 // [14]: /mail/
1949 // [15]: inbox
1950 // [16]: ?msg=1234&type=unread
1951 // [17]: #msg-content
1952 //
1953 urlParseRE: /^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
1954
1955 // Abstraction to address xss (Issue #4787) by removing the authority in
1956 // browsers that auto decode it. All references to location.href should be
1957 // replaced with a call to this method so that it can be dealt with properly here
1958 getLocation: function( url ) {
1959 var uri = url ? this.parseUrl( url ) : location,
1960 hash = this.parseUrl( url || location.href ).hash;
1961
1962 // mimic the browser with an empty string when the hash is empty
1963 hash = hash === "#" ? "" : hash;
1964
1965 // Make sure to parse the url or the location object for the hash because using location.hash
1966 // is autodecoded in firefox, the rest of the url should be from the object (location unless
1967 // we're testing) to avoid the inclusion of the authority
1968 return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
1969 },
1970
1971 parseLocation: function() {
1972 return this.parseUrl( this.getLocation() );
1973 },
1974
1975 //Parse a URL into a structure that allows easy access to
1976 //all of the URL components by name.
1977 parseUrl: function( url ) {
1978 // If we're passed an object, we'll assume that it is
1979 // a parsed url object and just return it back to the caller.
1980 if ( $.type( url ) === "object" ) {
1981 return url;
1982 }
1983
1984 var matches = path.urlParseRE.exec( url || "" ) || [];
1985
1986 // Create an object that allows the caller to access the sub-matches
1987 // by name. Note that IE returns an empty string instead of undefined,
1988 // like all other browsers do, so we normalize everything so its consistent
1989 // no matter what browser we're running on.
1990 return {
1991 href: matches[ 0 ] || "",
1992 hrefNoHash: matches[ 1 ] || "",
1993 hrefNoSearch: matches[ 2 ] || "",
1994 domain: matches[ 3 ] || "",
1995 protocol: matches[ 4 ] || "",
1996 doubleSlash: matches[ 5 ] || "",
1997 authority: matches[ 6 ] || "",
1998 username: matches[ 8 ] || "",
1999 password: matches[ 9 ] || "",
2000 host: matches[ 10 ] || "",
2001 hostname: matches[ 11 ] || "",
2002 port: matches[ 12 ] || "",
2003 pathname: matches[ 13 ] || "",
2004 directory: matches[ 14 ] || "",
2005 filename: matches[ 15 ] || "",
2006 search: matches[ 16 ] || "",
2007 hash: matches[ 17 ] || ""
2008 };
2009 },
2010
2011 //Turn relPath into an asbolute path. absPath is
2012 //an optional absolute path which describes what
2013 //relPath is relative to.
2014 makePathAbsolute: function( relPath, absPath ) {
2015 if ( relPath && relPath.charAt( 0 ) === "/" ) {
2016 return relPath;
2017 }
2018
2019 relPath = relPath || "";
2020 absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
2021
2022 var absStack = absPath ? absPath.split( "/" ) : [],
2023 relStack = relPath.split( "/" );
2024 for ( var i = 0; i < relStack.length; i++ ) {
2025 var d = relStack[ i ];
2026 switch ( d ) {
2027 case ".":
2028 break;
2029 case "..":
2030 if ( absStack.length ) {
2031 absStack.pop();
2032 }
2033 break;
2034 default:
2035 absStack.push( d );
2036 break;
2037 }
2038 }
2039 return "/" + absStack.join( "/" );
2040 },
2041
2042 //Returns true if both urls have the same domain.
2043 isSameDomain: function( absUrl1, absUrl2 ) {
2044 return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
2045 },
2046
2047 //Returns true for any relative variant.
2048 isRelativeUrl: function( url ) {
2049 // All relative Url variants have one thing in common, no protocol.
2050 return path.parseUrl( url ).protocol === "";
2051 },
2052
2053 //Returns true for an absolute url.
2054 isAbsoluteUrl: function( url ) {
2055 return path.parseUrl( url ).protocol !== "";
2056 },
2057
2058 //Turn the specified realtive URL into an absolute one. This function
2059 //can handle all relative variants (protocol, site, document, query, fragment).
2060 makeUrlAbsolute: function( relUrl, absUrl ) {
2061 if ( !path.isRelativeUrl( relUrl ) ) {
2062 return relUrl;
2063 }
2064
2065 if ( absUrl === undefined ) {
2066 absUrl = this.documentBase;
2067 }
2068
2069 var relObj = path.parseUrl( relUrl ),
2070 absObj = path.parseUrl( absUrl ),
2071 protocol = relObj.protocol || absObj.protocol,
2072 doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
2073 authority = relObj.authority || absObj.authority,
2074 hasPath = relObj.pathname !== "",
2075 pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
2076 search = relObj.search || ( !hasPath && absObj.search ) || "",
2077 hash = relObj.hash;
2078
2079 return protocol + doubleSlash + authority + pathname + search + hash;
2080 },
2081
2082 //Add search (aka query) params to the specified url.
2083 addSearchParams: function( url, params ) {
2084 var u = path.parseUrl( url ),
2085 p = ( typeof params === "object" ) ? $.param( params ) : params,
2086 s = u.search || "?";
2087 return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
2088 },
2089
2090 convertUrlToDataUrl: function( absUrl ) {
2091 var u = path.parseUrl( absUrl );
2092 if ( path.isEmbeddedPage( u ) ) {
2093 // For embedded pages, remove the dialog hash key as in getFilePath(),
2094 // and remove otherwise the Data Url won't match the id of the embedded Page.
2095 return u.hash
2096 .split( dialogHashKey )[0]
2097 .replace( /^#/, "" )
2098 .replace( /\?.*$/, "" );
2099 } else if ( path.isSameDomain( u, this.documentBase ) ) {
2100 return u.hrefNoHash.replace( this.documentBase.domain, "" ).split( dialogHashKey )[0];
2101 }
2102
2103 return window.decodeURIComponent(absUrl);
2104 },
2105
2106 //get path from current hash, or from a file path
2107 get: function( newPath ) {
2108 if ( newPath === undefined ) {
2109 newPath = path.parseLocation().hash;
2110 }
2111 return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
2112 },
2113
2114 //set location hash to path
2115 set: function( path ) {
2116 location.hash = path;
2117 },
2118
2119 //test if a given url (string) is a path
2120 //NOTE might be exceptionally naive
2121 isPath: function( url ) {
2122 return ( /\// ).test( url );
2123 },
2124
2125 //return a url path with the window's location protocol/hostname/pathname removed
2126 clean: function( url ) {
2127 return url.replace( this.documentBase.domain, "" );
2128 },
2129
2130 //just return the url without an initial #
2131 stripHash: function( url ) {
2132 return url.replace( /^#/, "" );
2133 },
2134
2135 stripQueryParams: function( url ) {
2136 return url.replace( /\?.*$/, "" );
2137 },
2138
2139 //remove the preceding hash, any query params, and dialog notations
2140 cleanHash: function( hash ) {
2141 return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
2142 },
2143
2144 isHashValid: function( hash ) {
2145 return ( /^#[^#]+$/ ).test( hash );
2146 },
2147
2148 //check whether a url is referencing the same domain, or an external domain or different protocol
2149 //could be mailto, etc
2150 isExternal: function( url ) {
2151 var u = path.parseUrl( url );
2152 return u.protocol && u.domain !== this.documentUrl.domain ? true : false;
2153 },
2154
2155 hasProtocol: function( url ) {
2156 return ( /^(:?\w+:)/ ).test( url );
2157 },
2158
2159 isEmbeddedPage: function( url ) {
2160 var u = path.parseUrl( url );
2161
2162 //if the path is absolute, then we need to compare the url against
2163 //both the this.documentUrl and the documentBase. The main reason for this
2164 //is that links embedded within external documents will refer to the
2165 //application document, whereas links embedded within the application
2166 //document will be resolved against the document base.
2167 if ( u.protocol !== "" ) {
2168 return ( !this.isPath(u.hash) && u.hash && ( u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ) ) );
2169 }
2170 return ( /^#/ ).test( u.href );
2171 },
2172
2173 squash: function( url, resolutionUrl ) {
2174 var state, href, cleanedUrl, search, stateIndex,
2175 isPath = this.isPath( url ),
2176 uri = this.parseUrl( url ),
2177 preservedHash = uri.hash,
2178 uiState = "";
2179
2180 // produce a url against which we can resole the provided path
2181 resolutionUrl = resolutionUrl || (path.isPath(url) ? path.getLocation() : path.getDocumentUrl());
2182
2183 // If the url is anything but a simple string, remove any preceding hash
2184 // eg #foo/bar -> foo/bar
2185 // #foo -> #foo
2186 cleanedUrl = isPath ? path.stripHash( url ) : url;
2187
2188 // If the url is a full url with a hash check if the parsed hash is a path
2189 // if it is, strip the #, and use it otherwise continue without change
2190 cleanedUrl = path.isPath( uri.hash ) ? path.stripHash( uri.hash ) : cleanedUrl;
2191
2192 // Split the UI State keys off the href
2193 stateIndex = cleanedUrl.indexOf( this.uiStateKey );
2194
2195 // store the ui state keys for use
2196 if( stateIndex > -1 ){
2197 uiState = cleanedUrl.slice( stateIndex );
2198 cleanedUrl = cleanedUrl.slice( 0, stateIndex );
2199 }
2200
2201 // make the cleanedUrl absolute relative to the resolution url
2202 href = path.makeUrlAbsolute( cleanedUrl, resolutionUrl );
2203
2204 // grab the search from the resolved url since parsing from
2205 // the passed url may not yield the correct result
2206 search = this.parseUrl( href ).search;
2207
2208 // TODO all this crap is terrible, clean it up
2209 if ( isPath ) {
2210 // reject the hash if it's a path or it's just a dialog key
2211 if( path.isPath( preservedHash ) || preservedHash.replace("#", "").indexOf( this.uiStateKey ) === 0) {
2212 preservedHash = "";
2213 }
2214
2215 // Append the UI State keys where it exists and it's been removed
2216 // from the url
2217 if( uiState && preservedHash.indexOf( this.uiStateKey ) === -1){
2218 preservedHash += uiState;
2219 }
2220
2221 // make sure that pound is on the front of the hash
2222 if( preservedHash.indexOf( "#" ) === -1 && preservedHash !== "" ){
2223 preservedHash = "#" + preservedHash;
2224 }
2225
2226 // reconstruct each of the pieces with the new search string and hash
2227 href = path.parseUrl( href );
2228 href = href.protocol + "//" + href.host + href.pathname + search + preservedHash;
2229 } else {
2230 href += href.indexOf( "#" ) > -1 ? uiState : "#" + uiState;
2231 }
2232
2233 return href;
2234 },
2235
2236 isPreservableHash: function( hash ) {
2237 return hash.replace( "#", "" ).indexOf( this.uiStateKey ) === 0;
2238 }
2239 };
2240
2241 path.documentUrl = path.parseLocation();
2242
2243 $base = $( "head" ).find( "base" );
2244
2245 path.documentBase = $base.length ?
2246 path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), path.documentUrl.href ) ) :
2247 path.documentUrl;
2248
2249 path.documentBaseDiffers = (path.documentUrl.hrefNoHash !== path.documentBase.hrefNoHash);
2250
2251 //return the original document url
2252 path.getDocumentUrl = function( asParsedObject ) {
2253 return asParsedObject ? $.extend( {}, path.documentUrl ) : path.documentUrl.href;
2254 };
2255
2256 //return the original document base url
2257 path.getDocumentBase = function( asParsedObject ) {
2258 return asParsedObject ? $.extend( {}, path.documentBase ) : path.documentBase.href;
2259 };
2260})( jQuery );
2261
2262
2263
2264(function( $, undefined ) {
2265 var path = $.mobile.path;
2266
2267 $.mobile.History = function( stack, index ) {
2268 this.stack = stack || [];
2269 this.activeIndex = index || 0;
2270 };
2271
2272 $.extend($.mobile.History.prototype, {
2273 getActive: function() {
2274 return this.stack[ this.activeIndex ];
2275 },
2276
2277 getLast: function() {
2278 return this.stack[ this.previousIndex ];
2279 },
2280
2281 getNext: function() {
2282 return this.stack[ this.activeIndex + 1 ];
2283 },
2284
2285 getPrev: function() {
2286 return this.stack[ this.activeIndex - 1 ];
2287 },
2288
2289 // addNew is used whenever a new page is added
2290 add: function( url, data ){
2291 data = data || {};
2292
2293 //if there's forward history, wipe it
2294 if ( this.getNext() ) {
2295 this.clearForward();
2296 }
2297
2298 // if the hash is included in the data make sure the shape
2299 // is consistent for comparison
2300 if( data.hash && data.hash.indexOf( "#" ) === -1) {
2301 data.hash = "#" + data.hash;
2302 }
2303
2304 data.url = url;
2305 this.stack.push( data );
2306 this.activeIndex = this.stack.length - 1;
2307 },
2308
2309 //wipe urls ahead of active index
2310 clearForward: function() {
2311 this.stack = this.stack.slice( 0, this.activeIndex + 1 );
2312 },
2313
2314 find: function( url, stack, earlyReturn ) {
2315 stack = stack || this.stack;
2316
2317 var entry, i, length = stack.length, index;
2318
2319 for ( i = 0; i < length; i++ ) {
2320 entry = stack[i];
2321
2322 if ( decodeURIComponent(url) === decodeURIComponent(entry.url) ||
2323 decodeURIComponent(url) === decodeURIComponent(entry.hash) ) {
2324 index = i;
2325
2326 if( earlyReturn ) {
2327 return index;
2328 }
2329 }
2330 }
2331
2332 return index;
2333 },
2334
2335 closest: function( url ) {
2336 var closest, a = this.activeIndex;
2337
2338 // First, take the slice of the history stack before the current index and search
2339 // for a url match. If one is found, we'll avoid avoid looking through forward history
2340 // NOTE the preference for backward history movement is driven by the fact that
2341 // most mobile browsers only have a dedicated back button, and users rarely use
2342 // the forward button in desktop browser anyhow
2343 closest = this.find( url, this.stack.slice(0, a) );
2344
2345 // If nothing was found in backward history check forward. The `true`
2346 // value passed as the third parameter causes the find method to break
2347 // on the first match in the forward history slice. The starting index
2348 // of the slice must then be added to the result to get the element index
2349 // in the original history stack :( :(
2350 //
2351 // TODO this is hyper confusing and should be cleaned up (ugh so bad)
2352 if( closest === undefined ) {
2353 closest = this.find( url, this.stack.slice(a), true );
2354 closest = closest === undefined ? closest : closest + a;
2355 }
2356
2357 return closest;
2358 },
2359
2360 direct: function( opts ) {
2361 var newActiveIndex = this.closest( opts.url ), a = this.activeIndex;
2362
2363 // save new page index, null check to prevent falsey 0 result
2364 // record the previous index for reference
2365 if( newActiveIndex !== undefined ) {
2366 this.activeIndex = newActiveIndex;
2367 this.previousIndex = a;
2368 }
2369
2370 // invoke callbacks where appropriate
2371 //
2372 // TODO this is also convoluted and confusing
2373 if ( newActiveIndex < a ) {
2374 ( opts.present || opts.back || $.noop )( this.getActive(), 'back' );
2375 } else if ( newActiveIndex > a ) {
2376 ( opts.present || opts.forward || $.noop )( this.getActive(), 'forward' );
2377 } else if ( newActiveIndex === undefined && opts.missing ){
2378 opts.missing( this.getActive() );
2379 }
2380 }
2381 });
2382})( jQuery );
2383
2384
2385(function( $, undefined ) {
2386 var path = $.mobile.path,
2387 initialHref = location.href;
2388
2389 $.mobile.Navigator = function( history ) {
2390 this.history = history;
2391 this.ignoreInitialHashChange = true;
2392
2393 $.mobile.window.bind({
2394 "popstate.history": $.proxy( this.popstate, this ),
2395 "hashchange.history": $.proxy( this.hashchange, this )
2396 });
2397 };
2398
2399 $.extend($.mobile.Navigator.prototype, {
2400 squash: function( url, data ) {
2401 var state, href, hash = path.isPath(url) ? path.stripHash(url) : url;
2402
2403 href = path.squash( url );
2404
2405 // make sure to provide this information when it isn't explicitly set in the
2406 // data object that was passed to the squash method
2407 state = $.extend({
2408 hash: hash,
2409 url: href
2410 }, data);
2411
2412 // replace the current url with the new href and store the state
2413 // Note that in some cases we might be replacing an url with the
2414 // same url. We do this anyways because we need to make sure that
2415 // all of our history entries have a state object associated with
2416 // them. This allows us to work around the case where $.mobile.back()
2417 // is called to transition from an external page to an embedded page.
2418 // In that particular case, a hashchange event is *NOT* generated by the browser.
2419 // Ensuring each history entry has a state object means that onPopState()
2420 // will always trigger our hashchange callback even when a hashchange event
2421 // is not fired.
2422 window.history.replaceState( state, state.title || document.title, href );
2423
2424 return state;
2425 },
2426
2427 hash: function( url, href ) {
2428 var parsed, loc, hash;
2429
2430 // Grab the hash for recording. If the passed url is a path
2431 // we used the parsed version of the squashed url to reconstruct,
2432 // otherwise we assume it's a hash and store it directly
2433 parsed = path.parseUrl( url );
2434 loc = path.parseLocation();
2435
2436 if( loc.pathname + loc.search === parsed.pathname + parsed.search ) {
2437 // If the pathname and search of the passed url is identical to the current loc
2438 // then we must use the hash. Otherwise there will be no event
2439 // eg, url = "/foo/bar?baz#bang", location.href = "http://example.com/foo/bar?baz"
2440 hash = parsed.hash ? parsed.hash : parsed.pathname + parsed.search;
2441 } else if ( path.isPath(url) ) {
2442 var resolved = path.parseUrl( href );
2443 // If the passed url is a path, make it domain relative and remove any trailing hash
2444 hash = resolved.pathname + resolved.search + (path.isPreservableHash( resolved.hash )? resolved.hash.replace( "#", "" ) : "");
2445 } else {
2446 hash = url;
2447 }
2448
2449 return hash;
2450 },
2451
2452 // TODO reconsider name
2453 go: function( url, data, noEvents ) {
2454 var state, href, hash, popstateEvent,
2455 isPopStateEvent = $.event.special.navigate.isPushStateEnabled();
2456
2457 // Get the url as it would look squashed on to the current resolution url
2458 href = path.squash( url );
2459
2460 // sort out what the hash sould be from the url
2461 hash = this.hash( url, href );
2462
2463 // Here we prevent the next hash change or popstate event from doing any
2464 // history management. In the case of hashchange we don't swallow it
2465 // if there will be no hashchange fired (since that won't reset the value)
2466 // and will swallow the following hashchange
2467 if( noEvents && hash !== path.stripHash(path.parseLocation().hash) ) {
2468 this.preventNextHashChange = noEvents;
2469 }
2470
2471 // IMPORTANT in the case where popstate is supported the event will be triggered
2472 // directly, stopping further execution - ie, interupting the flow of this
2473 // method call to fire bindings at this expression. Below the navigate method
2474 // there is a binding to catch this event and stop its propagation.
2475 //
2476 // We then trigger a new popstate event on the window with a null state
2477 // so that the navigate events can conclude their work properly
2478 //
2479 // if the url is a path we want to preserve the query params that are available on
2480 // the current url.
2481 this.preventHashAssignPopState = true;
2482 window.location.hash = hash;
2483
2484 // If popstate is enabled and the browser triggers `popstate` events when the hash
2485 // is set (this often happens immediately in browsers like Chrome), then the
2486 // this flag will be set to false already. If it's a browser that does not trigger
2487 // a `popstate` on hash assignement or `replaceState` then we need avoid the branch
2488 // that swallows the event created by the popstate generated by the hash assignment
2489 // At the time of this writing this happens with Opera 12 and some version of IE
2490 this.preventHashAssignPopState = false;
2491
2492 state = $.extend({
2493 url: href,
2494 hash: hash,
2495 title: document.title
2496 }, data);
2497
2498 if( isPopStateEvent ) {
2499 popstateEvent = new $.Event( "popstate" );
2500 popstateEvent.originalEvent = {
2501 type: "popstate",
2502 state: null
2503 };
2504
2505 this.squash( url, state );
2506
2507 // Trigger a new faux popstate event to replace the one that we
2508 // caught that was triggered by the hash setting above.
2509 if( !noEvents ) {
2510 this.ignorePopState = true;
2511 $.mobile.window.trigger( popstateEvent );
2512 }
2513 }
2514
2515 // record the history entry so that the information can be included
2516 // in hashchange event driven navigate events in a similar fashion to
2517 // the state that's provided by popstate
2518 this.history.add( state.url, state );
2519 },
2520
2521
2522 // This binding is intended to catch the popstate events that are fired
2523 // when execution of the `$.navigate` method stops at window.location.hash = url;
2524 // and completely prevent them from propagating. The popstate event will then be
2525 // retriggered after execution resumes
2526 //
2527 // TODO grab the original event here and use it for the synthetic event in the
2528 // second half of the navigate execution that will follow this binding
2529 popstate: function( event ) {
2530 var active, hash, state, closestIndex;
2531
2532 // Partly to support our test suite which manually alters the support
2533 // value to test hashchange. Partly to prevent all around weirdness
2534 if( !$.event.special.navigate.isPushStateEnabled() ){
2535 return;
2536 }
2537
2538 // If this is the popstate triggered by the actual alteration of the hash
2539 // prevent it completely. History is tracked manually
2540 if( this.preventHashAssignPopState ) {
2541 this.preventHashAssignPopState = false;
2542 event.stopImmediatePropagation();
2543 return;
2544 }
2545
2546 // if this is the popstate triggered after the `replaceState` call in the go
2547 // method, then simply ignore it. The history entry has already been captured
2548 if( this.ignorePopState ) {
2549 this.ignorePopState = false;
2550 return;
2551 }
2552
2553 // If there is no state, and the history stack length is one were
2554 // probably getting the page load popstate fired by browsers like chrome
2555 // avoid it and set the one time flag to false.
2556 // TODO: Do we really need all these conditions? Comparing location hrefs
2557 // should be sufficient.
2558 if( !event.originalEvent.state &&
2559 this.history.stack.length === 1 &&
2560 this.ignoreInitialHashChange ) {
2561 this.ignoreInitialHashChange = false;
2562
2563 if ( location.href === initialHref ) {
2564 event.preventDefault();
2565 return;
2566 }
2567 }
2568
2569 // account for direct manipulation of the hash. That is, we will receive a popstate
2570 // when the hash is changed by assignment, and it won't have a state associated. We
2571 // then need to squash the hash. See below for handling of hash assignment that
2572 // matches an existing history entry
2573 // TODO it might be better to only add to the history stack
2574 // when the hash is adjacent to the active history entry
2575 hash = path.parseLocation().hash;
2576 if( !event.originalEvent.state && hash ) {
2577 // squash the hash that's been assigned on the URL with replaceState
2578 // also grab the resulting state object for storage
2579 state = this.squash( hash );
2580
2581 // record the new hash as an additional history entry
2582 // to match the browser's treatment of hash assignment
2583 this.history.add( state.url, state );
2584
2585 // pass the newly created state information
2586 // along with the event
2587 event.historyState = state;
2588
2589 // do not alter history, we've added a new history entry
2590 // so we know where we are
2591 return;
2592 }
2593
2594 // If all else fails this is a popstate that comes from the back or forward buttons
2595 // make sure to set the state of our history stack properly, and record the directionality
2596 this.history.direct({
2597 url: (event.originalEvent.state || {}).url || hash,
2598
2599 // When the url is either forward or backward in history include the entry
2600 // as data on the event object for merging as data in the navigate event
2601 present: function( historyEntry, direction ) {
2602 // make sure to create a new object to pass down as the navigate event data
2603 event.historyState = $.extend({}, historyEntry);
2604 event.historyState.direction = direction;
2605 }
2606 });
2607 },
2608
2609 // NOTE must bind before `navigate` special event hashchange binding otherwise the
2610 // navigation data won't be attached to the hashchange event in time for those
2611 // bindings to attach it to the `navigate` special event
2612 // TODO add a check here that `hashchange.navigate` is bound already otherwise it's
2613 // broken (exception?)
2614 hashchange: function( event ) {
2615 var history, hash;
2616
2617 // If hashchange listening is explicitly disabled or pushstate is supported
2618 // avoid making use of the hashchange handler.
2619 if(!$.event.special.navigate.isHashChangeEnabled() ||
2620 $.event.special.navigate.isPushStateEnabled() ) {
2621 return;
2622 }
2623
2624 // On occasion explicitly want to prevent the next hash from propogating because we only
2625 // with to alter the url to represent the new state do so here
2626 if( this.preventNextHashChange ){
2627 this.preventNextHashChange = false;
2628 event.stopImmediatePropagation();
2629 return;
2630 }
2631
2632 history = this.history;
2633 hash = path.parseLocation().hash;
2634
2635 // If this is a hashchange caused by the back or forward button
2636 // make sure to set the state of our history stack properly
2637 this.history.direct({
2638 url: hash,
2639
2640 // When the url is either forward or backward in history include the entry
2641 // as data on the event object for merging as data in the navigate event
2642 present: function( historyEntry, direction ) {
2643 // make sure to create a new object to pass down as the navigate event data
2644 event.hashchangeState = $.extend({}, historyEntry);
2645 event.hashchangeState.direction = direction;
2646 },
2647
2648 // When we don't find a hash in our history clearly we're aiming to go there
2649 // record the entry as new for future traversal
2650 //
2651 // NOTE it's not entirely clear that this is the right thing to do given that we
2652 // can't know the users intention. It might be better to explicitly _not_
2653 // support location.hash assignment in preference to $.navigate calls
2654 // TODO first arg to add should be the href, but it causes issues in identifying
2655 // embeded pages
2656 missing: function() {
2657 history.add( hash, {
2658 hash: hash,
2659 title: document.title
2660 });
2661 }
2662 });
2663 }
2664 });
2665})( jQuery );
2666
2667
2668
2669(function( $, undefined ) {
2670 // TODO consider queueing navigation activity until previous activities have completed
2671 // so that end users don't have to think about it. Punting for now
2672 // TODO !! move the event bindings into callbacks on the navigate event
2673 $.mobile.navigate = function( url, data, noEvents ) {
2674 $.mobile.navigate.navigator.go( url, data, noEvents );
2675 };
2676
2677 // expose the history on the navigate method in anticipation of full integration with
2678 // existing navigation functionalty that is tightly coupled to the history information
2679 $.mobile.navigate.history = new $.mobile.History();
2680
2681 // instantiate an instance of the navigator for use within the $.navigate method
2682 $.mobile.navigate.navigator = new $.mobile.Navigator( $.mobile.navigate.history );
2683
2684 var loc = $.mobile.path.parseLocation();
2685 $.mobile.navigate.history.add( loc.href, {hash: loc.hash} );
2686})( jQuery );
2687
2688
2689// This plugin is an experiment for abstracting away the touch and mouse
2690// events so that developers don't have to worry about which method of input
2691// the device their document is loaded on supports.
2692//
2693// The idea here is to allow the developer to register listeners for the
2694// basic mouse events, such as mousedown, mousemove, mouseup, and click,
2695// and the plugin will take care of registering the correct listeners
2696// behind the scenes to invoke the listener at the fastest possible time
2697// for that device, while still retaining the order of event firing in
2698// the traditional mouse environment, should multiple handlers be registered
2699// on the same element for different events.
2700//
2701// The current version exposes the following virtual events to jQuery bind methods:
2702// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
2703
2704(function( $, window, document, undefined ) {
2705
2706var dataPropertyName = "virtualMouseBindings",
2707 touchTargetPropertyName = "virtualTouchID",
2708 virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
2709 touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
2710 mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [],
2711 mouseEventProps = $.event.props.concat( mouseHookProps ),
2712 activeDocHandlers = {},
2713 resetTimerID = 0,
2714 startX = 0,
2715 startY = 0,
2716 didScroll = false,
2717 clickBlockList = [],
2718 blockMouseTriggers = false,
2719 blockTouchTriggers = false,
2720 eventCaptureSupported = "addEventListener" in document,
2721 $document = $( document ),
2722 nextTouchID = 1,
2723 lastTouchID = 0, threshold;
2724
2725$.vmouse = {
2726 moveDistanceThreshold: 10,
2727 clickDistanceThreshold: 10,
2728 resetTimerDuration: 1500
2729};
2730
2731function getNativeEvent( event ) {
2732
2733 while ( event && typeof event.originalEvent !== "undefined" ) {
2734 event = event.originalEvent;
2735 }
2736 return event;
2737}
2738
2739function createVirtualEvent( event, eventType ) {
2740
2741 var t = event.type,
2742 oe, props, ne, prop, ct, touch, i, j, len;
2743
2744 event = $.Event( event );
2745 event.type = eventType;
2746
2747 oe = event.originalEvent;
2748 props = $.event.props;
2749
2750 // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
2751 // https://github.com/jquery/jquery-mobile/issues/3280
2752 if ( t.search( /^(mouse|click)/ ) > -1 ) {
2753 props = mouseEventProps;
2754 }
2755
2756 // copy original event properties over to the new event
2757 // this would happen if we could call $.event.fix instead of $.Event
2758 // but we don't have a way to force an event to be fixed multiple times
2759 if ( oe ) {
2760 for ( i = props.length, prop; i; ) {
2761 prop = props[ --i ];
2762 event[ prop ] = oe[ prop ];
2763 }
2764 }
2765
2766 // make sure that if the mouse and click virtual events are generated
2767 // without a .which one is defined
2768 if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) {
2769 event.which = 1;
2770 }
2771
2772 if ( t.search(/^touch/) !== -1 ) {
2773 ne = getNativeEvent( oe );
2774 t = ne.touches;
2775 ct = ne.changedTouches;
2776 touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined );
2777
2778 if ( touch ) {
2779 for ( j = 0, len = touchEventProps.length; j < len; j++) {
2780 prop = touchEventProps[ j ];
2781 event[ prop ] = touch[ prop ];
2782 }
2783 }
2784 }
2785
2786 return event;
2787}
2788
2789function getVirtualBindingFlags( element ) {
2790
2791 var flags = {},
2792 b, k;
2793
2794 while ( element ) {
2795
2796 b = $.data( element, dataPropertyName );
2797
2798 for ( k in b ) {
2799 if ( b[ k ] ) {
2800 flags[ k ] = flags.hasVirtualBinding = true;
2801 }
2802 }
2803 element = element.parentNode;
2804 }
2805 return flags;
2806}
2807
2808function getClosestElementWithVirtualBinding( element, eventType ) {
2809 var b;
2810 while ( element ) {
2811
2812 b = $.data( element, dataPropertyName );
2813
2814 if ( b && ( !eventType || b[ eventType ] ) ) {
2815 return element;
2816 }
2817 element = element.parentNode;
2818 }
2819 return null;
2820}
2821
2822function enableTouchBindings() {
2823 blockTouchTriggers = false;
2824}
2825
2826function disableTouchBindings() {
2827 blockTouchTriggers = true;
2828}
2829
2830function enableMouseBindings() {
2831 lastTouchID = 0;
2832 clickBlockList.length = 0;
2833 blockMouseTriggers = false;
2834
2835 // When mouse bindings are enabled, our
2836 // touch bindings are disabled.
2837 disableTouchBindings();
2838}
2839
2840function disableMouseBindings() {
2841 // When mouse bindings are disabled, our
2842 // touch bindings are enabled.
2843 enableTouchBindings();
2844}
2845
2846function startResetTimer() {
2847 clearResetTimer();
2848 resetTimerID = setTimeout( function() {
2849 resetTimerID = 0;
2850 enableMouseBindings();
2851 }, $.vmouse.resetTimerDuration );
2852}
2853
2854function clearResetTimer() {
2855 if ( resetTimerID ) {
2856 clearTimeout( resetTimerID );
2857 resetTimerID = 0;
2858 }
2859}
2860
2861function triggerVirtualEvent( eventType, event, flags ) {
2862 var ve;
2863
2864 if ( ( flags && flags[ eventType ] ) ||
2865 ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
2866
2867 ve = createVirtualEvent( event, eventType );
2868
2869 $( event.target).trigger( ve );
2870 }
2871
2872 return ve;
2873}
2874
2875function mouseEventCallback( event ) {
2876 var touchID = $.data( event.target, touchTargetPropertyName );
2877
2878 if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) {
2879 var ve = triggerVirtualEvent( "v" + event.type, event );
2880 if ( ve ) {
2881 if ( ve.isDefaultPrevented() ) {
2882 event.preventDefault();
2883 }
2884 if ( ve.isPropagationStopped() ) {
2885 event.stopPropagation();
2886 }
2887 if ( ve.isImmediatePropagationStopped() ) {
2888 event.stopImmediatePropagation();
2889 }
2890 }
2891 }
2892}
2893
2894function handleTouchStart( event ) {
2895
2896 var touches = getNativeEvent( event ).touches,
2897 target, flags;
2898
2899 if ( touches && touches.length === 1 ) {
2900
2901 target = event.target;
2902 flags = getVirtualBindingFlags( target );
2903
2904 if ( flags.hasVirtualBinding ) {
2905
2906 lastTouchID = nextTouchID++;
2907 $.data( target, touchTargetPropertyName, lastTouchID );
2908
2909 clearResetTimer();
2910
2911 disableMouseBindings();
2912 didScroll = false;
2913
2914 var t = getNativeEvent( event ).touches[ 0 ];
2915 startX = t.pageX;
2916 startY = t.pageY;
2917
2918 triggerVirtualEvent( "vmouseover", event, flags );
2919 triggerVirtualEvent( "vmousedown", event, flags );
2920 }
2921 }
2922}
2923
2924function handleScroll( event ) {
2925 if ( blockTouchTriggers ) {
2926 return;
2927 }
2928
2929 if ( !didScroll ) {
2930 triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
2931 }
2932
2933 didScroll = true;
2934 startResetTimer();
2935}
2936
2937function handleTouchMove( event ) {
2938 if ( blockTouchTriggers ) {
2939 return;
2940 }
2941
2942 var t = getNativeEvent( event ).touches[ 0 ],
2943 didCancel = didScroll,
2944 moveThreshold = $.vmouse.moveDistanceThreshold,
2945 flags = getVirtualBindingFlags( event.target );
2946
2947 didScroll = didScroll ||
2948 ( Math.abs( t.pageX - startX ) > moveThreshold ||
2949 Math.abs( t.pageY - startY ) > moveThreshold );
2950
2951
2952 if ( didScroll && !didCancel ) {
2953 triggerVirtualEvent( "vmousecancel", event, flags );
2954 }
2955
2956 triggerVirtualEvent( "vmousemove", event, flags );
2957 startResetTimer();
2958}
2959
2960function handleTouchEnd( event ) {
2961 if ( blockTouchTriggers ) {
2962 return;
2963 }
2964
2965 disableTouchBindings();
2966
2967 var flags = getVirtualBindingFlags( event.target ),
2968 t;
2969 triggerVirtualEvent( "vmouseup", event, flags );
2970
2971 if ( !didScroll ) {
2972 var ve = triggerVirtualEvent( "vclick", event, flags );
2973 if ( ve && ve.isDefaultPrevented() ) {
2974 // The target of the mouse events that follow the touchend
2975 // event don't necessarily match the target used during the
2976 // touch. This means we need to rely on coordinates for blocking
2977 // any click that is generated.
2978 t = getNativeEvent( event ).changedTouches[ 0 ];
2979 clickBlockList.push({
2980 touchID: lastTouchID,
2981 x: t.clientX,
2982 y: t.clientY
2983 });
2984
2985 // Prevent any mouse events that follow from triggering
2986 // virtual event notifications.
2987 blockMouseTriggers = true;
2988 }
2989 }
2990 triggerVirtualEvent( "vmouseout", event, flags);
2991 didScroll = false;
2992
2993 startResetTimer();
2994}
2995
2996function hasVirtualBindings( ele ) {
2997 var bindings = $.data( ele, dataPropertyName ),
2998 k;
2999
3000 if ( bindings ) {
3001 for ( k in bindings ) {
3002 if ( bindings[ k ] ) {
3003 return true;
3004 }
3005 }
3006 }
3007 return false;
3008}
3009
3010function dummyMouseHandler() {}
3011
3012function getSpecialEventObject( eventType ) {
3013 var realType = eventType.substr( 1 );
3014
3015 return {
3016 setup: function( data, namespace ) {
3017 // If this is the first virtual mouse binding for this element,
3018 // add a bindings object to its data.
3019
3020 if ( !hasVirtualBindings( this ) ) {
3021 $.data( this, dataPropertyName, {} );
3022 }
3023
3024 // If setup is called, we know it is the first binding for this
3025 // eventType, so initialize the count for the eventType to zero.
3026 var bindings = $.data( this, dataPropertyName );
3027 bindings[ eventType ] = true;
3028
3029 // If this is the first virtual mouse event for this type,
3030 // register a global handler on the document.
3031
3032 activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
3033
3034 if ( activeDocHandlers[ eventType ] === 1 ) {
3035 $document.bind( realType, mouseEventCallback );
3036 }
3037
3038 // Some browsers, like Opera Mini, won't dispatch mouse/click events
3039 // for elements unless they actually have handlers registered on them.
3040 // To get around this, we register dummy handlers on the elements.
3041
3042 $( this ).bind( realType, dummyMouseHandler );
3043
3044 // For now, if event capture is not supported, we rely on mouse handlers.
3045 if ( eventCaptureSupported ) {
3046 // If this is the first virtual mouse binding for the document,
3047 // register our touchstart handler on the document.
3048
3049 activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
3050
3051 if ( activeDocHandlers[ "touchstart" ] === 1 ) {
3052 $document.bind( "touchstart", handleTouchStart )
3053 .bind( "touchend", handleTouchEnd )
3054
3055 // On touch platforms, touching the screen and then dragging your finger
3056 // causes the window content to scroll after some distance threshold is
3057 // exceeded. On these platforms, a scroll prevents a click event from being
3058 // dispatched, and on some platforms, even the touchend is suppressed. To
3059 // mimic the suppression of the click event, we need to watch for a scroll
3060 // event. Unfortunately, some platforms like iOS don't dispatch scroll
3061 // events until *AFTER* the user lifts their finger (touchend). This means
3062 // we need to watch both scroll and touchmove events to figure out whether
3063 // or not a scroll happenens before the touchend event is fired.
3064
3065 .bind( "touchmove", handleTouchMove )
3066 .bind( "scroll", handleScroll );
3067 }
3068 }
3069 },
3070
3071 teardown: function( data, namespace ) {
3072 // If this is the last virtual binding for this eventType,
3073 // remove its global handler from the document.
3074
3075 --activeDocHandlers[ eventType ];
3076
3077 if ( !activeDocHandlers[ eventType ] ) {
3078 $document.unbind( realType, mouseEventCallback );
3079 }
3080
3081 if ( eventCaptureSupported ) {
3082 // If this is the last virtual mouse binding in existence,
3083 // remove our document touchstart listener.
3084
3085 --activeDocHandlers[ "touchstart" ];
3086
3087 if ( !activeDocHandlers[ "touchstart" ] ) {
3088 $document.unbind( "touchstart", handleTouchStart )
3089 .unbind( "touchmove", handleTouchMove )
3090 .unbind( "touchend", handleTouchEnd )
3091 .unbind( "scroll", handleScroll );
3092 }
3093 }
3094
3095 var $this = $( this ),
3096 bindings = $.data( this, dataPropertyName );
3097
3098 // teardown may be called when an element was
3099 // removed from the DOM. If this is the case,
3100 // jQuery core may have already stripped the element
3101 // of any data bindings so we need to check it before
3102 // using it.
3103 if ( bindings ) {
3104 bindings[ eventType ] = false;
3105 }
3106
3107 // Unregister the dummy event handler.
3108
3109 $this.unbind( realType, dummyMouseHandler );
3110
3111 // If this is the last virtual mouse binding on the
3112 // element, remove the binding data from the element.
3113
3114 if ( !hasVirtualBindings( this ) ) {
3115 $this.removeData( dataPropertyName );
3116 }
3117 }
3118 };
3119}
3120
3121// Expose our custom events to the jQuery bind/unbind mechanism.
3122
3123for ( var i = 0; i < virtualEventNames.length; i++ ) {
3124 $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
3125}
3126
3127// Add a capture click handler to block clicks.
3128// Note that we require event capture support for this so if the device
3129// doesn't support it, we punt for now and rely solely on mouse events.
3130if ( eventCaptureSupported ) {
3131 document.addEventListener( "click", function( e ) {
3132 var cnt = clickBlockList.length,
3133 target = e.target,
3134 x, y, ele, i, o, touchID;
3135
3136 if ( cnt ) {
3137 x = e.clientX;
3138 y = e.clientY;
3139 threshold = $.vmouse.clickDistanceThreshold;
3140
3141 // The idea here is to run through the clickBlockList to see if
3142 // the current click event is in the proximity of one of our
3143 // vclick events that had preventDefault() called on it. If we find
3144 // one, then we block the click.
3145 //
3146 // Why do we have to rely on proximity?
3147 //
3148 // Because the target of the touch event that triggered the vclick
3149 // can be different from the target of the click event synthesized
3150 // by the browser. The target of a mouse/click event that is syntehsized
3151 // from a touch event seems to be implementation specific. For example,
3152 // some browsers will fire mouse/click events for a link that is near
3153 // a touch event, even though the target of the touchstart/touchend event
3154 // says the user touched outside the link. Also, it seems that with most
3155 // browsers, the target of the mouse/click event is not calculated until the
3156 // time it is dispatched, so if you replace an element that you touched
3157 // with another element, the target of the mouse/click will be the new
3158 // element underneath that point.
3159 //
3160 // Aside from proximity, we also check to see if the target and any
3161 // of its ancestors were the ones that blocked a click. This is necessary
3162 // because of the strange mouse/click target calculation done in the
3163 // Android 2.1 browser, where if you click on an element, and there is a
3164 // mouse/click handler on one of its ancestors, the target will be the
3165 // innermost child of the touched element, even if that child is no where
3166 // near the point of touch.
3167
3168 ele = target;
3169
3170 while ( ele ) {
3171 for ( i = 0; i < cnt; i++ ) {
3172 o = clickBlockList[ i ];
3173 touchID = 0;
3174
3175 if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
3176 $.data( ele, touchTargetPropertyName ) === o.touchID ) {
3177 // XXX: We may want to consider removing matches from the block list
3178 // instead of waiting for the reset timer to fire.
3179 e.preventDefault();
3180 e.stopPropagation();
3181 return;
3182 }
3183 }
3184 ele = ele.parentNode;
3185 }
3186 }
3187 }, true);
3188}
3189})( jQuery, window, document );
3190
3191
3192(function( $, window, undefined ) {
3193 var $document = $( document );
3194
3195 // add new event shortcuts
3196 $.each( ( "touchstart touchmove touchend " +
3197 "tap taphold " +
3198 "swipe swipeleft swiperight " +
3199 "scrollstart scrollstop" ).split( " " ), function( i, name ) {
3200
3201 $.fn[ name ] = function( fn ) {
3202 return fn ? this.bind( name, fn ) : this.trigger( name );
3203 };
3204
3205 // jQuery < 1.8
3206 if ( $.attrFn ) {
3207 $.attrFn[ name ] = true;
3208 }
3209 });
3210
3211 var supportTouch = $.mobile.support.touch,
3212 scrollEvent = "touchmove scroll",
3213 touchStartEvent = supportTouch ? "touchstart" : "mousedown",
3214 touchStopEvent = supportTouch ? "touchend" : "mouseup",
3215 touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
3216
3217 function triggerCustomEvent( obj, eventType, event ) {
3218 var originalType = event.type;
3219 event.type = eventType;
3220 $.event.dispatch.call( obj, event );
3221 event.type = originalType;
3222 }
3223
3224 // also handles scrollstop
3225 $.event.special.scrollstart = {
3226
3227 enabled: true,
3228
3229 setup: function() {
3230
3231 var thisObject = this,
3232 $this = $( thisObject ),
3233 scrolling,
3234 timer;
3235
3236 function trigger( event, state ) {
3237 scrolling = state;
3238 triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
3239 }
3240
3241 // iPhone triggers scroll after a small delay; use touchmove instead
3242 $this.bind( scrollEvent, function( event ) {
3243
3244 if ( !$.event.special.scrollstart.enabled ) {
3245 return;
3246 }
3247
3248 if ( !scrolling ) {
3249 trigger( event, true );
3250 }
3251
3252 clearTimeout( timer );
3253 timer = setTimeout( function() {
3254 trigger( event, false );
3255 }, 50 );
3256 });
3257 }
3258 };
3259
3260 // also handles taphold
3261 $.event.special.tap = {
3262 tapholdThreshold: 750,
3263
3264 setup: function() {
3265 var thisObject = this,
3266 $this = $( thisObject );
3267
3268 $this.bind( "vmousedown", function( event ) {
3269
3270 if ( event.which && event.which !== 1 ) {
3271 return false;
3272 }
3273
3274 var origTarget = event.target,
3275 origEvent = event.originalEvent,
3276 timer;
3277
3278 function clearTapTimer() {
3279 clearTimeout( timer );
3280 }
3281
3282 function clearTapHandlers() {
3283 clearTapTimer();
3284
3285 $this.unbind( "vclick", clickHandler )
3286 .unbind( "vmouseup", clearTapTimer );
3287 $document.unbind( "vmousecancel", clearTapHandlers );
3288 }
3289
3290 function clickHandler( event ) {
3291 clearTapHandlers();
3292
3293 // ONLY trigger a 'tap' event if the start target is
3294 // the same as the stop target.
3295 if ( origTarget === event.target ) {
3296 triggerCustomEvent( thisObject, "tap", event );
3297 }
3298 }
3299
3300 $this.bind( "vmouseup", clearTapTimer )
3301 .bind( "vclick", clickHandler );
3302 $document.bind( "vmousecancel", clearTapHandlers );
3303
3304 timer = setTimeout( function() {
3305 triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) );
3306 }, $.event.special.tap.tapholdThreshold );
3307 });
3308 }
3309 };
3310
3311 // also handles swipeleft, swiperight
3312 $.event.special.swipe = {
3313 scrollSupressionThreshold: 30, // More than this horizontal displacement, and we will suppress scrolling.
3314
3315 durationThreshold: 1000, // More time than this, and it isn't a swipe.
3316
3317 horizontalDistanceThreshold: 30, // Swipe horizontal displacement must be more than this.
3318
3319 verticalDistanceThreshold: 75, // Swipe vertical displacement must be less than this.
3320
3321 start: function( event ) {
3322 var data = event.originalEvent.touches ?
3323 event.originalEvent.touches[ 0 ] : event;
3324 return {
3325 time: ( new Date() ).getTime(),
3326 coords: [ data.pageX, data.pageY ],
3327 origin: $( event.target )
3328 };
3329 },
3330
3331 stop: function( event ) {
3332 var data = event.originalEvent.touches ?
3333 event.originalEvent.touches[ 0 ] : event;
3334 return {
3335 time: ( new Date() ).getTime(),
3336 coords: [ data.pageX, data.pageY ]
3337 };
3338 },
3339
3340 handleSwipe: function( start, stop ) {
3341 if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
3342 Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
3343 Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
3344
3345 start.origin.trigger( "swipe" )
3346 .trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
3347 }
3348 },
3349
3350 setup: function() {
3351 var thisObject = this,
3352 $this = $( thisObject );
3353
3354 $this.bind( touchStartEvent, function( event ) {
3355 var start = $.event.special.swipe.start( event ),
3356 stop;
3357
3358 function moveHandler( event ) {
3359 if ( !start ) {
3360 return;
3361 }
3362
3363 stop = $.event.special.swipe.stop( event );
3364
3365 // prevent scrolling
3366 if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
3367 event.preventDefault();
3368 }
3369 }
3370
3371 $this.bind( touchMoveEvent, moveHandler )
3372 .one( touchStopEvent, function() {
3373 $this.unbind( touchMoveEvent, moveHandler );
3374
3375 if ( start && stop ) {
3376 $.event.special.swipe.handleSwipe( start, stop );
3377 }
3378 start = stop = undefined;
3379 });
3380 });
3381 }
3382 };
3383 $.each({
3384 scrollstop: "scrollstart",
3385 taphold: "tap",
3386 swipeleft: "swipe",
3387 swiperight: "swipe"
3388 }, function( event, sourceEvent ) {
3389
3390 $.event.special[ event ] = {
3391 setup: function() {
3392 $( this ).bind( sourceEvent, $.noop );
3393 }
3394 };
3395 });
3396
3397})( jQuery, this );
3398
3399
3400 // throttled resize event
3401 (function( $ ) {
3402 $.event.special.throttledresize = {
3403 setup: function() {
3404 $( this ).bind( "resize", handler );
3405 },
3406 teardown: function() {
3407 $( this ).unbind( "resize", handler );
3408 }
3409 };
3410
3411 var throttle = 250,
3412 handler = function() {
3413 curr = ( new Date() ).getTime();
3414 diff = curr - lastCall;
3415
3416 if ( diff >= throttle ) {
3417
3418 lastCall = curr;
3419 $( this ).trigger( "throttledresize" );
3420
3421 } else {
3422
3423 if ( heldCall ) {
3424 clearTimeout( heldCall );
3425 }
3426
3427 // Promise a held call will still execute
3428 heldCall = setTimeout( handler, throttle - diff );
3429 }
3430 },
3431 lastCall = 0,
3432 heldCall,
3433 curr,
3434 diff;
3435 })( jQuery );
3436
3437(function( $, window ) {
3438 var win = $( window ),
3439 event_name = "orientationchange",
3440 special_event,
3441 get_orientation,
3442 last_orientation,
3443 initial_orientation_is_landscape,
3444 initial_orientation_is_default,
3445 portrait_map = { "0": true, "180": true };
3446
3447 // It seems that some device/browser vendors use window.orientation values 0 and 180 to
3448 // denote the "default" orientation. For iOS devices, and most other smart-phones tested,
3449 // the default orientation is always "portrait", but in some Android and RIM based tablets,
3450 // the default orientation is "landscape". The following code attempts to use the window
3451 // dimensions to figure out what the current orientation is, and then makes adjustments
3452 // to the to the portrait_map if necessary, so that we can properly decode the
3453 // window.orientation value whenever get_orientation() is called.
3454 //
3455 // Note that we used to use a media query to figure out what the orientation the browser
3456 // thinks it is in:
3457 //
3458 // initial_orientation_is_landscape = $.mobile.media("all and (orientation: landscape)");
3459 //
3460 // but there was an iPhone/iPod Touch bug beginning with iOS 4.2, up through iOS 5.1,
3461 // where the browser *ALWAYS* applied the landscape media query. This bug does not
3462 // happen on iPad.
3463
3464 if ( $.support.orientation ) {
3465
3466 // Check the window width and height to figure out what the current orientation
3467 // of the device is at this moment. Note that we've initialized the portrait map
3468 // values to 0 and 180, *AND* we purposely check for landscape so that if we guess
3469 // wrong, , we default to the assumption that portrait is the default orientation.
3470 // We use a threshold check below because on some platforms like iOS, the iPhone
3471 // form-factor can report a larger width than height if the user turns on the
3472 // developer console. The actual threshold value is somewhat arbitrary, we just
3473 // need to make sure it is large enough to exclude the developer console case.
3474
3475 var ww = window.innerWidth || win.width(),
3476 wh = window.innerHeight || win.height(),
3477 landscape_threshold = 50;
3478
3479 initial_orientation_is_landscape = ww > wh && ( ww - wh ) > landscape_threshold;
3480
3481
3482 // Now check to see if the current window.orientation is 0 or 180.
3483 initial_orientation_is_default = portrait_map[ window.orientation ];
3484
3485 // If the initial orientation is landscape, but window.orientation reports 0 or 180, *OR*
3486 // if the initial orientation is portrait, but window.orientation reports 90 or -90, we
3487 // need to flip our portrait_map values because landscape is the default orientation for
3488 // this device/browser.
3489 if ( ( initial_orientation_is_landscape && initial_orientation_is_default ) || ( !initial_orientation_is_landscape && !initial_orientation_is_default ) ) {
3490 portrait_map = { "-90": true, "90": true };
3491 }
3492 }
3493
3494 $.event.special.orientationchange = $.extend( {}, $.event.special.orientationchange, {
3495 setup: function() {
3496 // If the event is supported natively, return false so that jQuery
3497 // will bind to the event using DOM methods.
3498 if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
3499 return false;
3500 }
3501
3502 // Get the current orientation to avoid initial double-triggering.
3503 last_orientation = get_orientation();
3504
3505 // Because the orientationchange event doesn't exist, simulate the
3506 // event by testing window dimensions on resize.
3507 win.bind( "throttledresize", handler );
3508 },
3509 teardown: function() {
3510 // If the event is not supported natively, return false so that
3511 // jQuery will unbind the event using DOM methods.
3512 if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
3513 return false;
3514 }
3515
3516 // Because the orientationchange event doesn't exist, unbind the
3517 // resize event handler.
3518 win.unbind( "throttledresize", handler );
3519 },
3520 add: function( handleObj ) {
3521 // Save a reference to the bound event handler.
3522 var old_handler = handleObj.handler;
3523
3524
3525 handleObj.handler = function( event ) {
3526 // Modify event object, adding the .orientation property.
3527 event.orientation = get_orientation();
3528
3529 // Call the originally-bound event handler and return its result.
3530 return old_handler.apply( this, arguments );
3531 };
3532 }
3533 });
3534
3535 // If the event is not supported natively, this handler will be bound to
3536 // the window resize event to simulate the orientationchange event.
3537 function handler() {
3538 // Get the current orientation.
3539 var orientation = get_orientation();
3540
3541 if ( orientation !== last_orientation ) {
3542 // The orientation has changed, so trigger the orientationchange event.
3543 last_orientation = orientation;
3544 win.trigger( event_name );
3545 }
3546 }
3547
3548 // Get the current page orientation. This method is exposed publicly, should it
3549 // be needed, as jQuery.event.special.orientationchange.orientation()
3550 $.event.special.orientationchange.orientation = get_orientation = function() {
3551 var isPortrait = true, elem = document.documentElement;
3552
3553 // prefer window orientation to the calculation based on screensize as
3554 // the actual screen resize takes place before or after the orientation change event
3555 // has been fired depending on implementation (eg android 2.3 is before, iphone after).
3556 // More testing is required to determine if a more reliable method of determining the new screensize
3557 // is possible when orientationchange is fired. (eg, use media queries + element + opacity)
3558 if ( $.support.orientation ) {
3559 // if the window orientation registers as 0 or 180 degrees report
3560 // portrait, otherwise landscape
3561 isPortrait = portrait_map[ window.orientation ];
3562 } else {
3563 isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
3564 }
3565
3566 return isPortrait ? "portrait" : "landscape";
3567 };
3568
3569 $.fn[ event_name ] = function( fn ) {
3570 return fn ? this.bind( event_name, fn ) : this.trigger( event_name );
3571 };
3572
3573 // jQuery < 1.8
3574 if ( $.attrFn ) {
3575 $.attrFn[ event_name ] = true;
3576 }
3577
3578}( jQuery, this ));
3579
3580
3581
3582(function( $, undefined ) {
3583
3584$.widget( "mobile.page", $.mobile.widget, {
3585 options: {
3586 theme: "c",
3587 domCache: false,
3588 keepNativeDefault: ":jqmData(role='none'), :jqmData(role='nojs')"
3589 },
3590
3591 _create: function() {
3592 // if false is returned by the callbacks do not create the page
3593 if ( this._trigger( "beforecreate" ) === false ) {
3594 return false;
3595 }
3596
3597 this.element
3598 .attr( "tabindex", "0" )
3599 .addClass( "ui-page ui-body-" + this.options.theme );
3600
3601 this._on( this.element, {
3602 pagebeforehide: "removeContainerBackground",
3603 pagebeforeshow: "_handlePageBeforeShow"
3604 });
3605 },
3606
3607 _handlePageBeforeShow: function( e ) {
3608 this.setContainerBackground();
3609 },
3610
3611 removeContainerBackground: function() {
3612 $.mobile.pageContainer.removeClass( "ui-overlay-" + $.mobile.getInheritedTheme( this.element.parent() ) );
3613 },
3614
3615 // set the page container background to the page theme
3616 setContainerBackground: function( theme ) {
3617 if ( this.options.theme ) {
3618 $.mobile.pageContainer.addClass( "ui-overlay-" + ( theme || this.options.theme ) );
3619 }
3620 },
3621
3622 keepNativeSelector: function() {
3623 var options = this.options,
3624 keepNativeDefined = options.keepNative && $.trim( options.keepNative );
3625
3626 if ( keepNativeDefined && options.keepNative !== options.keepNativeDefault ) {
3627 return [options.keepNative, options.keepNativeDefault].join( ", " );
3628 }
3629
3630 return options.keepNativeDefault;
3631 }
3632});
3633})( jQuery );
3634
3635(function( $, window, undefined ) {
3636
3637var createHandler = function( sequential ) {
3638
3639 // Default to sequential
3640 if ( sequential === undefined ) {
3641 sequential = true;
3642 }
3643
3644 return function( name, reverse, $to, $from ) {
3645
3646 var deferred = new $.Deferred(),
3647 reverseClass = reverse ? " reverse" : "",
3648 active = $.mobile.urlHistory.getActive(),
3649 toScroll = active.lastScroll || $.mobile.defaultHomeScroll,
3650 screenHeight = $.mobile.getScreenHeight(),
3651 maxTransitionOverride = $.mobile.maxTransitionWidth !== false && $.mobile.window.width() > $.mobile.maxTransitionWidth,
3652 none = !$.support.cssTransitions || maxTransitionOverride || !name || name === "none" || Math.max( $.mobile.window.scrollTop(), toScroll ) > $.mobile.getMaxScrollForTransition(),
3653 toPreClass = " ui-page-pre-in",
3654 toggleViewportClass = function() {
3655 $.mobile.pageContainer.toggleClass( "ui-mobile-viewport-transitioning viewport-" + name );
3656 },
3657 scrollPage = function() {
3658 // By using scrollTo instead of silentScroll, we can keep things better in order
3659 // Just to be precautios, disable scrollstart listening like silentScroll would
3660 $.event.special.scrollstart.enabled = false;
3661
3662 window.scrollTo( 0, toScroll );
3663
3664 // reenable scrollstart listening like silentScroll would
3665 setTimeout( function() {
3666 $.event.special.scrollstart.enabled = true;
3667 }, 150 );
3668 },
3669 cleanFrom = function() {
3670 $from
3671 .removeClass( $.mobile.activePageClass + " out in reverse " + name )
3672 .height( "" );
3673 },
3674 startOut = function() {
3675 // if it's not sequential, call the doneOut transition to start the TO page animating in simultaneously
3676 if ( !sequential ) {
3677 doneOut();
3678 }
3679 else {
3680 $from.animationComplete( doneOut );
3681 }
3682
3683 // Set the from page's height and start it transitioning out
3684 // Note: setting an explicit height helps eliminate tiling in the transitions
3685 $from
3686 .height( screenHeight + $.mobile.window.scrollTop() )
3687 .addClass( name + " out" + reverseClass );
3688 },
3689
3690 doneOut = function() {
3691
3692 if ( $from && sequential ) {
3693 cleanFrom();
3694 }
3695
3696 startIn();
3697 },
3698
3699 startIn = function() {
3700
3701 // Prevent flickering in phonegap container: see comments at #4024 regarding iOS
3702 $to.css( "z-index", -10 );
3703
3704 $to.addClass( $.mobile.activePageClass + toPreClass );
3705
3706 // Send focus to page as it is now display: block
3707 $.mobile.focusPage( $to );
3708
3709 // Set to page height
3710 $to.height( screenHeight + toScroll );
3711
3712 scrollPage();
3713
3714 // Restores visibility of the new page: added together with $to.css( "z-index", -10 );
3715 $to.css( "z-index", "" );
3716
3717 if ( !none ) {
3718 $to.animationComplete( doneIn );
3719 }
3720
3721 $to
3722 .removeClass( toPreClass )
3723 .addClass( name + " in" + reverseClass );
3724
3725 if ( none ) {
3726 doneIn();
3727 }
3728
3729 },
3730
3731 doneIn = function() {
3732
3733 if ( !sequential ) {
3734
3735 if ( $from ) {
3736 cleanFrom();
3737 }
3738 }
3739
3740 $to
3741 .removeClass( "out in reverse " + name )
3742 .height( "" );
3743
3744 toggleViewportClass();
3745
3746 // In some browsers (iOS5), 3D transitions block the ability to scroll to the desired location during transition
3747 // This ensures we jump to that spot after the fact, if we aren't there already.
3748 if ( $.mobile.window.scrollTop() !== toScroll ) {
3749 scrollPage();
3750 }
3751
3752 deferred.resolve( name, reverse, $to, $from, true );
3753 };
3754
3755 toggleViewportClass();
3756
3757 if ( $from && !none ) {
3758 startOut();
3759 }
3760 else {
3761 doneOut();
3762 }
3763
3764 return deferred.promise();
3765 };
3766};
3767
3768// generate the handlers from the above
3769var sequentialHandler = createHandler(),
3770 simultaneousHandler = createHandler( false ),
3771 defaultGetMaxScrollForTransition = function() {
3772 return $.mobile.getScreenHeight() * 3;
3773 };
3774
3775// Make our transition handler the public default.
3776$.mobile.defaultTransitionHandler = sequentialHandler;
3777
3778//transition handler dictionary for 3rd party transitions
3779$.mobile.transitionHandlers = {
3780 "default": $.mobile.defaultTransitionHandler,
3781 "sequential": sequentialHandler,
3782 "simultaneous": simultaneousHandler
3783};
3784
3785$.mobile.transitionFallbacks = {};
3786
3787// If transition is defined, check if css 3D transforms are supported, and if not, if a fallback is specified
3788$.mobile._maybeDegradeTransition = function( transition ) {
3789 if ( transition && !$.support.cssTransform3d && $.mobile.transitionFallbacks[ transition ] ) {
3790 transition = $.mobile.transitionFallbacks[ transition ];
3791 }
3792
3793 return transition;
3794};
3795
3796// Set the getMaxScrollForTransition to default if no implementation was set by user
3797$.mobile.getMaxScrollForTransition = $.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition;
3798})( jQuery, this );
3799
3800(function( $, undefined ) {
3801
3802 //define vars for interal use
3803 var $window = $.mobile.window,
3804 $html = $( 'html' ),
3805 $head = $( 'head' ),
3806
3807 // NOTE: path extensions dependent on core attributes. Moved here to remove deps from
3808 // $.mobile.path definition
3809 path = $.extend($.mobile.path, {
3810
3811 //return the substring of a filepath before the sub-page key, for making a server request
3812 getFilePath: function( path ) {
3813 var splitkey = '&' + $.mobile.subPageUrlKey;
3814 return path && path.split( splitkey )[0].split( dialogHashKey )[0];
3815 },
3816
3817 //check if the specified url refers to the first page in the main application document.
3818 isFirstPageUrl: function( url ) {
3819 // We only deal with absolute paths.
3820 var u = path.parseUrl( path.makeUrlAbsolute( url, this.documentBase ) ),
3821
3822 // Does the url have the same path as the document?
3823 samePath = u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ),
3824
3825 // Get the first page element.
3826 fp = $.mobile.firstPage,
3827
3828 // Get the id of the first page element if it has one.
3829 fpId = fp && fp[0] ? fp[0].id : undefined;
3830
3831 // The url refers to the first page if the path matches the document and
3832 // it either has no hash value, or the hash is exactly equal to the id of the
3833 // first page element.
3834 return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
3835 },
3836
3837 // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
3838 // requests if the document doing the request was loaded via the file:// protocol.
3839 // This is usually to allow the application to "phone home" and fetch app specific
3840 // data. We normally let the browser handle external/cross-domain urls, but if the
3841 // allowCrossDomainPages option is true, we will allow cross-domain http/https
3842 // requests to go through our page loading logic.
3843 isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
3844 return $.mobile.allowCrossDomainPages &&
3845 docUrl.protocol === "file:" &&
3846 reqUrl.search( /^https?:/ ) !== -1;
3847 }
3848 }),
3849
3850 // used to track last vclicked element to make sure its value is added to form data
3851 $lastVClicked = null,
3852
3853 //will be defined when a link is clicked and given an active class
3854 $activeClickedLink = null,
3855
3856 // resolved on domready
3857 domreadyDeferred = $.Deferred(),
3858
3859 //urlHistory is purely here to make guesses at whether the back or forward button was clicked
3860 //and provide an appropriate transition
3861 urlHistory = $.mobile.navigate.history,
3862
3863 //define first selector to receive focus when a page is shown
3864 focusable = "[tabindex],a,button:visible,select:visible,input",
3865
3866 //queue to hold simultanious page transitions
3867 pageTransitionQueue = [],
3868
3869 //indicates whether or not page is in process of transitioning
3870 isPageTransitioning = false,
3871
3872 //nonsense hash change key for dialogs, so they create a history entry
3873 dialogHashKey = "&ui-state=dialog",
3874
3875 //existing base tag?
3876 $base = $head.children( "base" ),
3877
3878 //tuck away the original document URL minus any fragment.
3879 documentUrl = path.documentUrl,
3880
3881 //if the document has an embedded base tag, documentBase is set to its
3882 //initial value. If a base tag does not exist, then we default to the documentUrl.
3883 documentBase = path.documentBase,
3884
3885 //cache the comparison once.
3886 documentBaseDiffers = path.documentBaseDiffers,
3887
3888 getScreenHeight = $.mobile.getScreenHeight;
3889
3890 //base element management, defined depending on dynamic base tag support
3891 var base = $.support.dynamicBaseTag ? {
3892
3893 //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
3894 element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),
3895
3896 //set the generated BASE element's href attribute to a new page's base path
3897 set: function( href ) {
3898 href = path.parseUrl(href).hrefNoHash;
3899 base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
3900 },
3901
3902 //set the generated BASE element's href attribute to a new page's base path
3903 reset: function() {
3904 base.element.attr( "href", documentBase.hrefNoSearch );
3905 }
3906
3907 } : undefined;
3908
3909
3910 //return the original document url
3911 $.mobile.getDocumentUrl = path.getDocumentUrl;
3912
3913 //return the original document base url
3914 $.mobile.getDocumentBase = path.getDocumentBase;
3915
3916 /* internal utility functions */
3917
3918 // NOTE Issue #4950 Android phonegap doesn't navigate back properly
3919 // when a full page refresh has taken place. It appears that hashchange
3920 // and replacestate history alterations work fine but we need to support
3921 // both forms of history traversal in our code that uses backward history
3922 // movement
3923 $.mobile.back = function() {
3924 var nav = window.navigator;
3925
3926 // if the setting is on and the navigator object is
3927 // available use the phonegap navigation capability
3928 if( this.phonegapNavigationEnabled &&
3929 nav &&
3930 nav.app &&
3931 nav.app.backHistory ){
3932 nav.app.backHistory();
3933 } else {
3934 window.history.back();
3935 }
3936 };
3937
3938 //direct focus to the page title, or otherwise first focusable element
3939 $.mobile.focusPage = function ( page ) {
3940 var autofocus = page.find( "[autofocus]" ),
3941 pageTitle = page.find( ".ui-title:eq(0)" );
3942
3943 if ( autofocus.length ) {
3944 autofocus.focus();
3945 return;
3946 }
3947
3948 if ( pageTitle.length ) {
3949 pageTitle.focus();
3950 } else{
3951 page.focus();
3952 }
3953 };
3954
3955 //remove active classes after page transition or error
3956 function removeActiveLinkClass( forceRemoval ) {
3957 if ( !!$activeClickedLink && ( !$activeClickedLink.closest( "." + $.mobile.activePageClass ).length || forceRemoval ) ) {
3958 $activeClickedLink.removeClass( $.mobile.activeBtnClass );
3959 }
3960 $activeClickedLink = null;
3961 }
3962
3963 function releasePageTransitionLock() {
3964 isPageTransitioning = false;
3965 if ( pageTransitionQueue.length > 0 ) {
3966 $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
3967 }
3968 }
3969
3970 // Save the last scroll distance per page, before it is hidden
3971 var setLastScrollEnabled = true,
3972 setLastScroll, delayedSetLastScroll;
3973
3974 setLastScroll = function() {
3975 // this barrier prevents setting the scroll value based on the browser
3976 // scrolling the window based on a hashchange
3977 if ( !setLastScrollEnabled ) {
3978 return;
3979 }
3980
3981 var active = $.mobile.urlHistory.getActive();
3982
3983 if ( active ) {
3984 var lastScroll = $window.scrollTop();
3985
3986 // Set active page's lastScroll prop.
3987 // If the location we're scrolling to is less than minScrollBack, let it go.
3988 active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
3989 }
3990 };
3991
3992 // bind to scrollstop to gather scroll position. The delay allows for the hashchange
3993 // event to fire and disable scroll recording in the case where the browser scrolls
3994 // to the hash targets location (sometimes the top of the page). once pagechange fires
3995 // getLastScroll is again permitted to operate
3996 delayedSetLastScroll = function() {
3997 setTimeout( setLastScroll, 100 );
3998 };
3999
4000 // disable an scroll setting when a hashchange has been fired, this only works
4001 // because the recording of the scroll position is delayed for 100ms after
4002 // the browser might have changed the position because of the hashchange
4003 $window.bind( $.support.pushState ? "popstate" : "hashchange", function() {
4004 setLastScrollEnabled = false;
4005 });
4006
4007 // handle initial hashchange from chrome :(
4008 $window.one( $.support.pushState ? "popstate" : "hashchange", function() {
4009 setLastScrollEnabled = true;
4010 });
4011
4012 // wait until the mobile page container has been determined to bind to pagechange
4013 $window.one( "pagecontainercreate", function() {
4014 // once the page has changed, re-enable the scroll recording
4015 $.mobile.pageContainer.bind( "pagechange", function() {
4016
4017 setLastScrollEnabled = true;
4018
4019 // remove any binding that previously existed on the get scroll
4020 // which may or may not be different than the scroll element determined for
4021 // this page previously
4022 $window.unbind( "scrollstop", delayedSetLastScroll );
4023
4024 // determine and bind to the current scoll element which may be the window
4025 // or in the case of touch overflow the element with touch overflow
4026 $window.bind( "scrollstop", delayedSetLastScroll );
4027 });
4028 });
4029
4030 // bind to scrollstop for the first page as "pagechange" won't be fired in that case
4031 $window.bind( "scrollstop", delayedSetLastScroll );
4032
4033 // No-op implementation of transition degradation
4034 $.mobile._maybeDegradeTransition = $.mobile._maybeDegradeTransition || function( transition ) {
4035 return transition;
4036 };
4037
4038 //function for transitioning between two existing pages
4039 function transitionPages( toPage, fromPage, transition, reverse ) {
4040 if ( fromPage ) {
4041 //trigger before show/hide events
4042 fromPage.data( "mobile-page" )._trigger( "beforehide", null, { nextPage: toPage } );
4043 }
4044
4045 toPage.data( "mobile-page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );
4046
4047 //clear page loader
4048 $.mobile.hidePageLoadingMsg();
4049
4050 transition = $.mobile._maybeDegradeTransition( transition );
4051
4052 //find the transition handler for the specified transition. If there
4053 //isn't one in our transitionHandlers dictionary, use the default one.
4054 //call the handler immediately to kick-off the transition.
4055 var th = $.mobile.transitionHandlers[ transition || "default" ] || $.mobile.defaultTransitionHandler,
4056 promise = th( transition, reverse, toPage, fromPage );
4057
4058 promise.done(function() {
4059 //trigger show/hide events
4060 if ( fromPage ) {
4061 fromPage.data( "mobile-page" )._trigger( "hide", null, { nextPage: toPage } );
4062 }
4063
4064 //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
4065 toPage.data( "mobile-page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
4066 });
4067
4068 return promise;
4069 }
4070
4071 //simply set the active page's minimum height to screen height, depending on orientation
4072 $.mobile.resetActivePageHeight = function resetActivePageHeight( height ) {
4073 var aPage = $( "." + $.mobile.activePageClass ),
4074 aPagePadT = parseFloat( aPage.css( "padding-top" ) ),
4075 aPagePadB = parseFloat( aPage.css( "padding-bottom" ) ),
4076 aPageBorderT = parseFloat( aPage.css( "border-top-width" ) ),
4077 aPageBorderB = parseFloat( aPage.css( "border-bottom-width" ) );
4078
4079 height = ( typeof height === "number" )? height : getScreenHeight();
4080
4081 aPage.css( "min-height", height - aPagePadT - aPagePadB - aPageBorderT - aPageBorderB );
4082 };
4083
4084 //shared page enhancements
4085 function enhancePage( $page, role ) {
4086 // If a role was specified, make sure the data-role attribute
4087 // on the page element is in sync.
4088 if ( role ) {
4089 $page.attr( "data-" + $.mobile.ns + "role", role );
4090 }
4091
4092 //run page plugin
4093 $page.page();
4094 }
4095
4096 // determine the current base url
4097 function findBaseWithDefault() {
4098 var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
4099 return closestBase || documentBase.hrefNoHash;
4100 }
4101
4102 /* exposed $.mobile methods */
4103
4104 //animation complete callback
4105 $.fn.animationComplete = function( callback ) {
4106 if ( $.support.cssTransitions ) {
4107 return $( this ).one( 'webkitAnimationEnd animationend', callback );
4108 }
4109 else{
4110 // defer execution for consistency between webkit/non webkit
4111 setTimeout( callback, 0 );
4112 return $( this );
4113 }
4114 };
4115
4116 //expose path object on $.mobile
4117 $.mobile.path = path;
4118
4119 //expose base object on $.mobile
4120 $.mobile.base = base;
4121
4122 //history stack
4123 $.mobile.urlHistory = urlHistory;
4124
4125 $.mobile.dialogHashKey = dialogHashKey;
4126
4127 //enable cross-domain page support
4128 $.mobile.allowCrossDomainPages = false;
4129
4130 $.mobile._bindPageRemove = function() {
4131 var page = $( this );
4132
4133 // when dom caching is not enabled or the page is embedded bind to remove the page on hide
4134 if ( !page.data( "mobile-page" ).options.domCache &&
4135 page.is( ":jqmData(external-page='true')" ) ) {
4136
4137 page.bind( 'pagehide.remove', function( e ) {
4138 var $this = $( this ),
4139 prEvent = new $.Event( "pageremove" );
4140
4141 $this.trigger( prEvent );
4142
4143 if ( !prEvent.isDefaultPrevented() ) {
4144 $this.removeWithDependents();
4145 }
4146 });
4147 }
4148 };
4149
4150 // Load a page into the DOM.
4151 $.mobile.loadPage = function( url, options ) {
4152 // This function uses deferred notifications to let callers
4153 // know when the page is done loading, or if an error has occurred.
4154 var deferred = $.Deferred(),
4155
4156 // The default loadPage options with overrides specified by
4157 // the caller.
4158 settings = $.extend( {}, $.mobile.loadPage.defaults, options ),
4159
4160 // The DOM element for the page after it has been loaded.
4161 page = null,
4162
4163 // If the reloadPage option is true, and the page is already
4164 // in the DOM, dupCachedPage will be set to the page element
4165 // so that it can be removed after the new version of the
4166 // page is loaded off the network.
4167 dupCachedPage = null,
4168
4169 // The absolute version of the URL passed into the function. This
4170 // version of the URL may contain dialog/subpage params in it.
4171 absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );
4172
4173 // If the caller provided data, and we're using "get" request,
4174 // append the data to the URL.
4175 if ( settings.data && settings.type === "get" ) {
4176 absUrl = path.addSearchParams( absUrl, settings.data );
4177 settings.data = undefined;
4178 }
4179
4180 // If the caller is using a "post" request, reloadPage must be true
4181 if ( settings.data && settings.type === "post" ) {
4182 settings.reloadPage = true;
4183 }
4184
4185 // The absolute version of the URL minus any dialog/subpage params.
4186 // In otherwords the real URL of the page to be loaded.
4187 var fileUrl = path.getFilePath( absUrl ),
4188
4189 // The version of the Url actually stored in the data-url attribute of
4190 // the page. For embedded pages, it is just the id of the page. For pages
4191 // within the same domain as the document base, it is the site relative
4192 // path. For cross-domain pages (Phone Gap only) the entire absolute Url
4193 // used to load the page.
4194 dataUrl = path.convertUrlToDataUrl( absUrl );
4195
4196 // Make sure we have a pageContainer to work with.
4197 settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
4198
4199 // Check to see if the page already exists in the DOM.
4200 // NOTE do _not_ use the :jqmData psuedo selector because parenthesis
4201 // are a valid url char and it breaks on the first occurence
4202 page = settings.pageContainer.children( "[data-" + $.mobile.ns +"url='" + dataUrl + "']" );
4203
4204 // If we failed to find the page, check to see if the url is a
4205 // reference to an embedded page. If so, it may have been dynamically
4206 // injected by a developer, in which case it would be lacking a data-url
4207 // attribute and in need of enhancement.
4208 if ( page.length === 0 && dataUrl && !path.isPath( dataUrl ) ) {
4209 page = settings.pageContainer.children( "#" + dataUrl )
4210 .attr( "data-" + $.mobile.ns + "url", dataUrl )
4211 .jqmData( "url", dataUrl );
4212 }
4213
4214
4215 // If we failed to find a page in the DOM, check the URL to see if it
4216 // refers to the first page in the application. If it isn't a reference
4217 // to the first page and refers to non-existent embedded page, error out.
4218 if ( page.length === 0 ) {
4219 if ( $.mobile.firstPage && path.isFirstPageUrl( fileUrl ) ) {
4220 // Check to make sure our cached-first-page is actually
4221 // in the DOM. Some user deployed apps are pruning the first
4222 // page from the DOM for various reasons, we check for this
4223 // case here because we don't want a first-page with an id
4224 // falling through to the non-existent embedded page error
4225 // case. If the first-page is not in the DOM, then we let
4226 // things fall through to the ajax loading code below so
4227 // that it gets reloaded.
4228 if ( $.mobile.firstPage.parent().length ) {
4229 page = $( $.mobile.firstPage );
4230 }
4231 } else if ( path.isEmbeddedPage( fileUrl ) ) {
4232 deferred.reject( absUrl, options );
4233 return deferred.promise();
4234 }
4235 }
4236
4237 // If the page we are interested in is already in the DOM,
4238 // and the caller did not indicate that we should force a
4239 // reload of the file, we are done. Otherwise, track the
4240 // existing page as a duplicated.
4241 if ( page.length ) {
4242 if ( !settings.reloadPage ) {
4243 enhancePage( page, settings.role );
4244 deferred.resolve( absUrl, options, page );
4245 //if we are reloading the page make sure we update the base if its not a prefetch
4246 if( base && !options.prefetch ){
4247 base.set(url);
4248 }
4249 return deferred.promise();
4250 }
4251 dupCachedPage = page;
4252 }
4253 var mpc = settings.pageContainer,
4254 pblEvent = new $.Event( "pagebeforeload" ),
4255 triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };
4256
4257 // Let listeners know we're about to load a page.
4258 mpc.trigger( pblEvent, triggerData );
4259
4260 // If the default behavior is prevented, stop here!
4261 if ( pblEvent.isDefaultPrevented() ) {
4262 return deferred.promise();
4263 }
4264
4265 if ( settings.showLoadMsg ) {
4266
4267 // This configurable timeout allows cached pages a brief delay to load without showing a message
4268 var loadMsgDelay = setTimeout(function() {
4269 $.mobile.showPageLoadingMsg();
4270 }, settings.loadMsgDelay ),
4271
4272 // Shared logic for clearing timeout and removing message.
4273 hideMsg = function() {
4274
4275 // Stop message show timer
4276 clearTimeout( loadMsgDelay );
4277
4278 // Hide loading message
4279 $.mobile.hidePageLoadingMsg();
4280 };
4281 }
4282 // Reset base to the default document base.
4283 // only reset if we are not prefetching
4284 if ( base && ( typeof options === "undefined" || typeof options.prefetch === "undefined" ) ) {
4285 base.reset();
4286 }
4287
4288 if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
4289 deferred.reject( absUrl, options );
4290 } else {
4291 // Load the new page.
4292 $.ajax({
4293 url: fileUrl,
4294 type: settings.type,
4295 data: settings.data,
4296 contentType: settings.contentType,
4297 dataType: "html",
4298 success: function( html, textStatus, xhr ) {
4299 //pre-parse html to check for a data-url,
4300 //use it as the new fileUrl, base path, etc
4301 var all = $( "<div></div>" ),
4302
4303 //page title regexp
4304 newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,
4305
4306 // TODO handle dialogs again
4307 pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)" ),
4308 dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );
4309
4310
4311 // data-url must be provided for the base tag so resource requests can be directed to the
4312 // correct url. loading into a temprorary element makes these requests immediately
4313 if ( pageElemRegex.test( html ) &&
4314 RegExp.$1 &&
4315 dataUrlRegex.test( RegExp.$1 ) &&
4316 RegExp.$1 ) {
4317 url = fileUrl = path.getFilePath( $( "<div>" + RegExp.$1 + "</div>" ).text() );
4318 }
4319 //dont update the base tag if we are prefetching
4320 if ( base && ( typeof options === "undefined" || typeof options.prefetch === "undefined" )) {
4321 base.set( fileUrl );
4322 }
4323
4324 //workaround to allow scripts to execute when included in page divs
4325 all.get( 0 ).innerHTML = html;
4326 page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
4327
4328 //if page elem couldn't be found, create one and insert the body element's contents
4329 if ( !page.length ) {
4330 page = $( "<div data-" + $.mobile.ns + "role='page'>" + ( html.split( /<\/?body[^>]*>/gmi )[1] || "" ) + "</div>" );
4331 }
4332
4333 if ( newPageTitle && !page.jqmData( "title" ) ) {
4334 if ( ~newPageTitle.indexOf( "&" ) ) {
4335 newPageTitle = $( "<div>" + newPageTitle + "</div>" ).text();
4336 }
4337 page.jqmData( "title", newPageTitle );
4338 }
4339
4340 //rewrite src and href attrs to use a base url
4341 if ( !$.support.dynamicBaseTag ) {
4342 var newPath = path.get( fileUrl );
4343 page.find( "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]" ).each(function() {
4344 var thisAttr = $( this ).is( '[href]' ) ? 'href' :
4345 $( this ).is( '[src]' ) ? 'src' : 'action',
4346 thisUrl = $( this ).attr( thisAttr );
4347
4348 // XXX_jblas: We need to fix this so that it removes the document
4349 // base URL, and then prepends with the new page URL.
4350 //if full path exists and is same, chop it - helps IE out
4351 thisUrl = thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
4352
4353 if ( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
4354 $( this ).attr( thisAttr, newPath + thisUrl );
4355 }
4356 });
4357 }
4358
4359 //append to page and enhance
4360 // TODO taging a page with external to make sure that embedded pages aren't removed
4361 // by the various page handling code is bad. Having page handling code in many
4362 // places is bad. Solutions post 1.0
4363 page
4364 .attr( "data-" + $.mobile.ns + "url", path.convertUrlToDataUrl( fileUrl ) )
4365 .attr( "data-" + $.mobile.ns + "external-page", true )
4366 .appendTo( settings.pageContainer );
4367
4368 // wait for page creation to leverage options defined on widget
4369 page.one( 'pagecreate', $.mobile._bindPageRemove );
4370
4371 enhancePage( page, settings.role );
4372
4373 // Enhancing the page may result in new dialogs/sub pages being inserted
4374 // into the DOM. If the original absUrl refers to a sub-page, that is the
4375 // real page we are interested in.
4376 if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
4377 page = settings.pageContainer.children( "[data-" + $.mobile.ns +"url='" + dataUrl + "']" );
4378 }
4379
4380 // Remove loading message.
4381 if ( settings.showLoadMsg ) {
4382 hideMsg();
4383 }
4384
4385 // Add the page reference and xhr to our triggerData.
4386 triggerData.xhr = xhr;
4387 triggerData.textStatus = textStatus;
4388 triggerData.page = page;
4389
4390 // Let listeners know the page loaded successfully.
4391 settings.pageContainer.trigger( "pageload", triggerData );
4392
4393 deferred.resolve( absUrl, options, page, dupCachedPage );
4394 },
4395 error: function( xhr, textStatus, errorThrown ) {
4396 //set base back to current path
4397 if ( base ) {
4398 base.set( path.get() );
4399 }
4400
4401 // Add error info to our triggerData.
4402 triggerData.xhr = xhr;
4403 triggerData.textStatus = textStatus;
4404 triggerData.errorThrown = errorThrown;
4405
4406 var plfEvent = new $.Event( "pageloadfailed" );
4407
4408 // Let listeners know the page load failed.
4409 settings.pageContainer.trigger( plfEvent, triggerData );
4410
4411 // If the default behavior is prevented, stop here!
4412 // Note that it is the responsibility of the listener/handler
4413 // that called preventDefault(), to resolve/reject the
4414 // deferred object within the triggerData.
4415 if ( plfEvent.isDefaultPrevented() ) {
4416 return;
4417 }
4418
4419 // Remove loading message.
4420 if ( settings.showLoadMsg ) {
4421
4422 // Remove loading message.
4423 hideMsg();
4424
4425 // show error message
4426 $.mobile.showPageLoadingMsg( $.mobile.pageLoadErrorMessageTheme, $.mobile.pageLoadErrorMessage, true );
4427
4428 // hide after delay
4429 setTimeout( $.mobile.hidePageLoadingMsg, 1500 );
4430 }
4431
4432 deferred.reject( absUrl, options );
4433 }
4434 });
4435 }
4436
4437 return deferred.promise();
4438 };
4439
4440 $.mobile.loadPage.defaults = {
4441 type: "get",
4442 data: undefined,
4443 reloadPage: false,
4444 role: undefined, // By default we rely on the role defined by the @data-role attribute.
4445 showLoadMsg: false,
4446 pageContainer: undefined,
4447 loadMsgDelay: 50 // This delay allows loads that pull from browser cache to occur without showing the loading message.
4448 };
4449
4450 // Show a specific page in the page container.
4451 $.mobile.changePage = function( toPage, options ) {
4452 // If we are in the midst of a transition, queue the current request.
4453 // We'll call changePage() once we're done with the current transition to
4454 // service the request.
4455 if ( isPageTransitioning ) {
4456 pageTransitionQueue.unshift( arguments );
4457 return;
4458 }
4459
4460 var settings = $.extend( {}, $.mobile.changePage.defaults, options ), isToPageString;
4461
4462 // Make sure we have a pageContainer to work with.
4463 settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
4464
4465 // Make sure we have a fromPage.
4466 settings.fromPage = settings.fromPage || $.mobile.activePage;
4467
4468 isToPageString = (typeof toPage === "string");
4469
4470 var mpc = settings.pageContainer,
4471 pbcEvent = new $.Event( "pagebeforechange" ),
4472 triggerData = { toPage: toPage, options: settings };
4473
4474 // NOTE: preserve the original target as the dataUrl value will be simplified
4475 // eg, removing ui-state, and removing query params from the hash
4476 // this is so that users who want to use query params have access to them
4477 // in the event bindings for the page life cycle See issue #5085
4478 if ( isToPageString ) {
4479 // if the toPage is a string simply convert it
4480 triggerData.absUrl = path.makeUrlAbsolute( toPage, findBaseWithDefault() );
4481 } else {
4482 // if the toPage is a jQuery object grab the absolute url stored
4483 // in the loadPage callback where it exists
4484 triggerData.absUrl = toPage.data( 'absUrl' );
4485 }
4486
4487 // Let listeners know we're about to change the current page.
4488 mpc.trigger( pbcEvent, triggerData );
4489
4490 // If the default behavior is prevented, stop here!
4491 if ( pbcEvent.isDefaultPrevented() ) {
4492 return;
4493 }
4494
4495 // We allow "pagebeforechange" observers to modify the toPage in the trigger
4496 // data to allow for redirects. Make sure our toPage is updated.
4497 //
4498 // We also need to re-evaluate whether it is a string, because an object can
4499 // also be replaced by a string
4500
4501 toPage = triggerData.toPage;
4502 isToPageString = (typeof toPage === "string");
4503
4504 // Set the isPageTransitioning flag to prevent any requests from
4505 // entering this method while we are in the midst of loading a page
4506 // or transitioning.
4507 isPageTransitioning = true;
4508
4509 // If the caller passed us a url, call loadPage()
4510 // to make sure it is loaded into the DOM. We'll listen
4511 // to the promise object it returns so we know when
4512 // it is done loading or if an error ocurred.
4513 if ( isToPageString ) {
4514 // preserve the original target as the dataUrl value will be simplified
4515 // eg, removing ui-state, and removing query params from the hash
4516 // this is so that users who want to use query params have access to them
4517 // in the event bindings for the page life cycle See issue #5085
4518 settings.target = toPage;
4519
4520 $.mobile.loadPage( toPage, settings )
4521 .done(function( url, options, newPage, dupCachedPage ) {
4522 isPageTransitioning = false;
4523 options.duplicateCachedPage = dupCachedPage;
4524
4525 // store the original absolute url so that it can be provided
4526 // to events in the triggerData of the subsequent changePage call
4527 newPage.data( 'absUrl', triggerData.absUrl );
4528 $.mobile.changePage( newPage, options );
4529 })
4530 .fail(function( url, options ) {
4531
4532 //clear out the active button state
4533 removeActiveLinkClass( true );
4534
4535 //release transition lock so navigation is free again
4536 releasePageTransitionLock();
4537 settings.pageContainer.trigger( "pagechangefailed", triggerData );
4538 });
4539 return;
4540 }
4541
4542 // If we are going to the first-page of the application, we need to make
4543 // sure settings.dataUrl is set to the application document url. This allows
4544 // us to avoid generating a document url with an id hash in the case where the
4545 // first-page of the document has an id attribute specified.
4546 if ( toPage[ 0 ] === $.mobile.firstPage[ 0 ] && !settings.dataUrl ) {
4547 settings.dataUrl = documentUrl.hrefNoHash;
4548 }
4549
4550 // The caller passed us a real page DOM element. Update our
4551 // internal state and then trigger a transition to the page.
4552 var fromPage = settings.fromPage,
4553 url = ( settings.dataUrl && path.convertUrlToDataUrl( settings.dataUrl ) ) || toPage.jqmData( "url" ),
4554 // The pageUrl var is usually the same as url, except when url is obscured as a dialog url. pageUrl always contains the file path
4555 pageUrl = url,
4556 fileUrl = path.getFilePath( url ),
4557 active = urlHistory.getActive(),
4558 activeIsInitialPage = urlHistory.activeIndex === 0,
4559 historyDir = 0,
4560 pageTitle = document.title,
4561 isDialog = settings.role === "dialog" || toPage.jqmData( "role" ) === "dialog";
4562
4563
4564 // By default, we prevent changePage requests when the fromPage and toPage
4565 // are the same element, but folks that generate content manually/dynamically
4566 // and reuse pages want to be able to transition to the same page. To allow
4567 // this, they will need to change the default value of allowSamePageTransition
4568 // to true, *OR*, pass it in as an option when they manually call changePage().
4569 // It should be noted that our default transition animations assume that the
4570 // formPage and toPage are different elements, so they may behave unexpectedly.
4571 // It is up to the developer that turns on the allowSamePageTransitiona option
4572 // to either turn off transition animations, or make sure that an appropriate
4573 // animation transition is used.
4574 if ( fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition ) {
4575 isPageTransitioning = false;
4576 mpc.trigger( "pagechange", triggerData );
4577
4578 // Even if there is no page change to be done, we should keep the urlHistory in sync with the hash changes
4579 if ( settings.fromHashChange ) {
4580 urlHistory.direct({ url: url });
4581 }
4582
4583 return;
4584 }
4585
4586 // We need to make sure the page we are given has already been enhanced.
4587 enhancePage( toPage, settings.role );
4588
4589 // If the changePage request was sent from a hashChange event, check to see if the
4590 // page is already within the urlHistory stack. If so, we'll assume the user hit
4591 // the forward/back button and will try to match the transition accordingly.
4592 if ( settings.fromHashChange ) {
4593 historyDir = options.direction === "back" ? -1 : 1;
4594 }
4595
4596 // Kill the keyboard.
4597 // XXX_jblas: We need to stop crawling the entire document to kill focus. Instead,
4598 // we should be tracking focus with a delegate() handler so we already have
4599 // the element in hand at this point.
4600 // Wrap this in a try/catch block since IE9 throw "Unspecified error" if document.activeElement
4601 // is undefined when we are in an IFrame.
4602 try {
4603 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== 'body' ) {
4604 $( document.activeElement ).blur();
4605 } else {
4606 $( "input:focus, textarea:focus, select:focus" ).blur();
4607 }
4608 } catch( e ) {}
4609
4610 // 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
4611 var alreadyThere = false;
4612
4613 // If we're displaying the page as a dialog, we don't want the url
4614 // for the dialog content to be used in the hash. Instead, we want
4615 // to append the dialogHashKey to the url of the current page.
4616 if ( isDialog && active ) {
4617 // on the initial page load active.url is undefined and in that case should
4618 // be an empty string. Moving the undefined -> empty string back into
4619 // urlHistory.addNew seemed imprudent given undefined better represents
4620 // the url state
4621
4622 // If we are at a place in history that once belonged to a dialog, reuse
4623 // this state without adding to urlHistory and without modifying the hash.
4624 // However, if a dialog is already displayed at this point, and we're
4625 // about to display another dialog, then we must add another hash and
4626 // history entry on top so that one may navigate back to the original dialog
4627 if ( active.url &&
4628 active.url.indexOf( dialogHashKey ) > -1 &&
4629 $.mobile.activePage &&
4630 !$.mobile.activePage.is( ".ui-dialog" ) &&
4631 urlHistory.activeIndex > 0 ) {
4632 settings.changeHash = false;
4633 alreadyThere = true;
4634 }
4635
4636 // Normally, we tack on a dialog hash key, but if this is the location of a stale dialog,
4637 // we reuse the URL from the entry
4638 url = ( active.url || "" );
4639
4640 // account for absolute urls instead of just relative urls use as hashes
4641 if( !alreadyThere && url.indexOf("#") > -1 ) {
4642 url += dialogHashKey;
4643 } else {
4644 url += "#" + dialogHashKey;
4645 }
4646
4647 // tack on another dialogHashKey if this is the same as the initial hash
4648 // this makes sure that a history entry is created for this dialog
4649 if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
4650 url += dialogHashKey;
4651 }
4652 }
4653
4654 // if title element wasn't found, try the page div data attr too
4655 // If this is a deep-link or a reload ( active === undefined ) then just use pageTitle
4656 var newPageTitle = ( !active )? pageTitle : toPage.jqmData( "title" ) || toPage.children( ":jqmData(role='header')" ).find( ".ui-title" ).text();
4657 if ( !!newPageTitle && pageTitle === document.title ) {
4658 pageTitle = newPageTitle;
4659 }
4660 if ( !toPage.jqmData( "title" ) ) {
4661 toPage.jqmData( "title", pageTitle );
4662 }
4663
4664 // Make sure we have a transition defined.
4665 settings.transition = settings.transition ||
4666 ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined ) ||
4667 ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
4668
4669 //add page to history stack if it's not back or forward
4670 if ( !historyDir && alreadyThere ) {
4671 urlHistory.getActive().pageUrl = pageUrl;
4672 }
4673
4674 // Set the location hash.
4675 if ( url && !settings.fromHashChange ) {
4676 var params;
4677
4678 // rebuilding the hash here since we loose it earlier on
4679 // TODO preserve the originally passed in path
4680 if( !path.isPath( url ) && url.indexOf( "#" ) < 0 ) {
4681 url = "#" + url;
4682 }
4683
4684 // TODO the property names here are just silly
4685 params = {
4686 transition: settings.transition,
4687 title: pageTitle,
4688 pageUrl: pageUrl,
4689 role: settings.role
4690 };
4691
4692 if ( settings.changeHash !== false && $.mobile.hashListeningEnabled ) {
4693 $.mobile.navigate( url, params, true);
4694 } else if ( toPage[ 0 ] !== $.mobile.firstPage[ 0 ] ) {
4695 $.mobile.navigate.history.add( url, params );
4696 }
4697 }
4698
4699 //set page title
4700 document.title = pageTitle;
4701
4702 //set "toPage" as activePage
4703 $.mobile.activePage = toPage;
4704
4705 // If we're navigating back in the URL history, set reverse accordingly.
4706 settings.reverse = settings.reverse || historyDir < 0;
4707
4708 transitionPages( toPage, fromPage, settings.transition, settings.reverse )
4709 .done(function( name, reverse, $to, $from, alreadyFocused ) {
4710 removeActiveLinkClass();
4711
4712 //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
4713 if ( settings.duplicateCachedPage ) {
4714 settings.duplicateCachedPage.remove();
4715 }
4716
4717 // Send focus to the newly shown page. Moved from promise .done binding in transitionPages
4718 // itself to avoid ie bug that reports offsetWidth as > 0 (core check for visibility)
4719 // despite visibility: hidden addresses issue #2965
4720 // https://github.com/jquery/jquery-mobile/issues/2965
4721 if ( !alreadyFocused ) {
4722 $.mobile.focusPage( toPage );
4723 }
4724
4725 releasePageTransitionLock();
4726 mpc.trigger( "pagechange", triggerData );
4727 });
4728 };
4729
4730 $.mobile.changePage.defaults = {
4731 transition: undefined,
4732 reverse: false,
4733 changeHash: true,
4734 fromHashChange: false,
4735 role: undefined, // By default we rely on the role defined by the @data-role attribute.
4736 duplicateCachedPage: undefined,
4737 pageContainer: undefined,
4738 showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
4739 dataUrl: undefined,
4740 fromPage: undefined,
4741 allowSamePageTransition: false
4742 };
4743
4744/* Event Bindings - hashchange, submit, and click */
4745 function findClosestLink( ele )
4746 {
4747 while ( ele ) {
4748 // Look for the closest element with a nodeName of "a".
4749 // Note that we are checking if we have a valid nodeName
4750 // before attempting to access it. This is because the
4751 // node we get called with could have originated from within
4752 // an embedded SVG document where some symbol instance elements
4753 // don't have nodeName defined on them, or strings are of type
4754 // SVGAnimatedString.
4755 if ( ( typeof ele.nodeName === "string" ) && ele.nodeName.toLowerCase() === "a" ) {
4756 break;
4757 }
4758 ele = ele.parentNode;
4759 }
4760 return ele;
4761 }
4762
4763 // The base URL for any given element depends on the page it resides in.
4764 function getClosestBaseUrl( ele )
4765 {
4766 // Find the closest page and extract out its url.
4767 var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
4768 base = documentBase.hrefNoHash;
4769
4770 if ( !url || !path.isPath( url ) ) {
4771 url = base;
4772 }
4773
4774 return path.makeUrlAbsolute( url, base);
4775 }
4776
4777 //The following event bindings should be bound after mobileinit has been triggered
4778 //the following deferred is resolved in the init file
4779 $.mobile.navreadyDeferred = $.Deferred();
4780 $.mobile._registerInternalEvents = function() {
4781 var getAjaxFormData = function( $form, calculateOnly ) {
4782 var url, ret = true, formData, vclickedName, method;
4783
4784 if ( !$.mobile.ajaxEnabled ||
4785 // test that the form is, itself, ajax false
4786 $form.is( ":jqmData(ajax='false')" ) ||
4787 // test that $.mobile.ignoreContentEnabled is set and
4788 // the form or one of it's parents is ajax=false
4789 !$form.jqmHijackable().length ||
4790 $form.attr( "target" ) ) {
4791 return false;
4792 }
4793
4794 url = $form.attr( "action" );
4795 method = ( $form.attr( "method" ) || "get" ).toLowerCase();
4796
4797 // If no action is specified, browsers default to using the
4798 // URL of the document containing the form. Since we dynamically
4799 // pull in pages from external documents, the form should submit
4800 // to the URL for the source document of the page containing
4801 // the form.
4802 if ( !url ) {
4803 // Get the @data-url for the page containing the form.
4804 url = getClosestBaseUrl( $form );
4805
4806 // NOTE: If the method is "get", we need to strip off the query string
4807 // because it will get replaced with the new form data. See issue #5710.
4808 if ( method === "get" ) {
4809 url = path.parseUrl( url ).hrefNoSearch;
4810 }
4811
4812 if ( url === documentBase.hrefNoHash ) {
4813 // The url we got back matches the document base,
4814 // which means the page must be an internal/embedded page,
4815 // so default to using the actual document url as a browser
4816 // would.
4817 url = documentUrl.hrefNoSearch;
4818 }
4819 }
4820
4821 url = path.makeUrlAbsolute( url, getClosestBaseUrl( $form ) );
4822
4823 if ( ( path.isExternal( url ) && !path.isPermittedCrossDomainRequest( documentUrl, url ) ) ) {
4824 return false;
4825 }
4826
4827 if ( !calculateOnly ) {
4828 formData = $form.serializeArray();
4829
4830 if ( $lastVClicked && $lastVClicked[ 0 ].form === $form[ 0 ] ) {
4831 vclickedName = $lastVClicked.attr( "name" );
4832 if ( vclickedName ) {
4833 // Make sure the last clicked element is included in the form
4834 $.each( formData, function( key, value ) {
4835 if ( value.name === vclickedName ) {
4836 // Unset vclickedName - we've found it in the serialized data already
4837 vclickedName = "";
4838 return false;
4839 }
4840 });
4841 if ( vclickedName ) {
4842 formData.push( { name: vclickedName, value: $lastVClicked.attr( "value" ) } );
4843 }
4844 }
4845 }
4846
4847 ret = {
4848 url: url,
4849 options: {
4850 type: method,
4851 data: $.param( formData ),
4852 transition: $form.jqmData( "transition" ),
4853 reverse: $form.jqmData( "direction" ) === "reverse",
4854 reloadPage: true
4855 }
4856 };
4857 }
4858
4859 return ret;
4860 };
4861
4862 //bind to form submit events, handle with Ajax
4863 $.mobile.document.delegate( "form", "submit", function( event ) {
4864 var formData = getAjaxFormData( $( this ) );
4865
4866 if ( formData ) {
4867 $.mobile.changePage( formData.url, formData.options );
4868 event.preventDefault();
4869 }
4870 });
4871
4872 //add active state on vclick
4873 $.mobile.document.bind( "vclick", function( event ) {
4874 var $btn, btnEls, target = event.target, needClosest = false;
4875 // if this isn't a left click we don't care. Its important to note
4876 // that when the virtual event is generated it will create the which attr
4877 if ( event.which > 1 || !$.mobile.linkBindingEnabled ) {
4878 return;
4879 }
4880
4881 // Record that this element was clicked, in case we need it for correct
4882 // form submission during the "submit" handler above
4883 $lastVClicked = $( target );
4884
4885 // Try to find a target element to which the active class will be applied
4886 if ( $.data( target, "mobile-button" ) ) {
4887 // If the form will not be submitted via AJAX, do not add active class
4888 if ( !getAjaxFormData( $( target ).closest( "form" ), true ) ) {
4889 return;
4890 }
4891 // We will apply the active state to this button widget - the parent
4892 // of the input that was clicked will have the associated data
4893 if ( target.parentNode ) {
4894 target = target.parentNode;
4895 }
4896 } else {
4897 target = findClosestLink( target );
4898 if ( !( target && path.parseUrl( target.getAttribute( "href" ) || "#" ).hash !== "#" ) ) {
4899 return;
4900 }
4901
4902 // TODO teach $.mobile.hijackable to operate on raw dom elements so the
4903 // link wrapping can be avoided
4904 if ( !$( target ).jqmHijackable().length ) {
4905 return;
4906 }
4907 }
4908
4909 // Avoid calling .closest by using the data set during .buttonMarkup()
4910 // List items have the button data in the parent of the element clicked
4911 if ( !!~target.className.indexOf( "ui-link-inherit" ) ) {
4912 if ( target.parentNode ) {
4913 btnEls = $.data( target.parentNode, "buttonElements" );
4914 }
4915 // Otherwise, look for the data on the target itself
4916 } else {
4917 btnEls = $.data( target, "buttonElements" );
4918 }
4919 // If found, grab the button's outer element
4920 if ( btnEls ) {
4921 target = btnEls.outer;
4922 } else {
4923 needClosest = true;
4924 }
4925
4926 $btn = $( target );
4927 // If the outer element wasn't found by the our heuristics, use .closest()
4928 if ( needClosest ) {
4929 $btn = $btn.closest( ".ui-btn" );
4930 }
4931
4932 if ( $btn.length > 0 && !$btn.hasClass( "ui-disabled" ) ) {
4933 removeActiveLinkClass( true );
4934 $activeClickedLink = $btn;
4935 $activeClickedLink.addClass( $.mobile.activeBtnClass );
4936 }
4937 });
4938
4939 // click routing - direct to HTTP or Ajax, accordingly
4940 $.mobile.document.bind( "click", function( event ) {
4941 if ( !$.mobile.linkBindingEnabled || event.isDefaultPrevented() ) {
4942 return;
4943 }
4944
4945 var link = findClosestLink( event.target ), $link = $( link ), httpCleanup;
4946
4947 // If there is no link associated with the click or its not a left
4948 // click we want to ignore the click
4949 // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
4950 // can be avoided
4951 if ( !link || event.which > 1 || !$link.jqmHijackable().length ) {
4952 return;
4953 }
4954
4955 //remove active link class if external (then it won't be there if you come back)
4956 httpCleanup = function() {
4957 window.setTimeout(function() { removeActiveLinkClass( true ); }, 200 );
4958 };
4959
4960 //if there's a data-rel=back attr, go back in history
4961 if ( $link.is( ":jqmData(rel='back')" ) ) {
4962 $.mobile.back();
4963 return false;
4964 }
4965
4966 var baseUrl = getClosestBaseUrl( $link ),
4967
4968 //get href, if defined, otherwise default to empty hash
4969 href = path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
4970
4971 //if ajax is disabled, exit early
4972 if ( !$.mobile.ajaxEnabled && !path.isEmbeddedPage( href ) ) {
4973 httpCleanup();
4974 //use default click handling
4975 return;
4976 }
4977
4978 // XXX_jblas: Ideally links to application pages should be specified as
4979 // an url to the application document with a hash that is either
4980 // the site relative path or id to the page. But some of the
4981 // internal code that dynamically generates sub-pages for nested
4982 // lists and select dialogs, just write a hash in the link they
4983 // create. This means the actual URL path is based on whatever
4984 // the current value of the base tag is at the time this code
4985 // is called. For now we are just assuming that any url with a
4986 // hash in it is an application page reference.
4987 if ( href.search( "#" ) !== -1 ) {
4988 href = href.replace( /[^#]*#/, "" );
4989 if ( !href ) {
4990 //link was an empty hash meant purely
4991 //for interaction, so we ignore it.
4992 event.preventDefault();
4993 return;
4994 } else if ( path.isPath( href ) ) {
4995 //we have apath so make it the href we want to load.
4996 href = path.makeUrlAbsolute( href, baseUrl );
4997 } else {
4998 //we have a simple id so use the documentUrl as its base.
4999 href = path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
5000 }
5001 }
5002
5003 // Should we handle this link, or let the browser deal with it?
5004 var useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" ),
5005
5006 // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
5007 // requests if the document doing the request was loaded via the file:// protocol.
5008 // This is usually to allow the application to "phone home" and fetch app specific
5009 // data. We normally let the browser handle external/cross-domain urls, but if the
5010 // allowCrossDomainPages option is true, we will allow cross-domain http/https
5011 // requests to go through our page loading logic.
5012
5013 //check for protocol or rel and its not an embedded page
5014 //TODO overlap in logic from isExternal, rel=external check should be
5015 // moved into more comprehensive isExternalLink
5016 isExternal = useDefaultUrlHandling || ( path.isExternal( href ) && !path.isPermittedCrossDomainRequest( documentUrl, href ) );
5017
5018 if ( isExternal ) {
5019 httpCleanup();
5020 //use default click handling
5021 return;
5022 }
5023
5024 //use ajax
5025 var transition = $link.jqmData( "transition" ),
5026 reverse = $link.jqmData( "direction" ) === "reverse" ||
5027 // deprecated - remove by 1.0
5028 $link.jqmData( "back" ),
5029
5030 //this may need to be more specific as we use data-rel more
5031 role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
5032
5033 $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role, link: $link } );
5034 event.preventDefault();
5035 });
5036
5037 //prefetch pages when anchors with data-prefetch are encountered
5038 $.mobile.document.delegate( ".ui-page", "pageshow.prefetch", function() {
5039 var urls = [];
5040 $( this ).find( "a:jqmData(prefetch)" ).each(function() {
5041 var $link = $( this ),
5042 url = $link.attr( "href" );
5043
5044 if ( url && $.inArray( url, urls ) === -1 ) {
5045 urls.push( url );
5046
5047 $.mobile.loadPage( url, { role: $link.attr( "data-" + $.mobile.ns + "rel" ),prefetch: true } );
5048 }
5049 });
5050 });
5051
5052 $.mobile._handleHashChange = function( url, data ) {
5053 //find first page via hash
5054 var to = path.stripHash(url),
5055 //transition is false if it's the first page, undefined otherwise (and may be overridden by default)
5056 transition = $.mobile.urlHistory.stack.length === 0 ? "none" : undefined,
5057
5058 // default options for the changPage calls made after examining the current state
5059 // of the page and the hash, NOTE that the transition is derived from the previous
5060 // history entry
5061 changePageOptions = {
5062 changeHash: false,
5063 fromHashChange: true,
5064 reverse: data.direction === "back"
5065 };
5066
5067 $.extend( changePageOptions, data, {
5068 transition: (urlHistory.getLast() || {}).transition || transition
5069 });
5070
5071 // special case for dialogs
5072 if ( urlHistory.activeIndex > 0 && to.indexOf( dialogHashKey ) > -1 && urlHistory.initialDst !== to ) {
5073
5074 // If current active page is not a dialog skip the dialog and continue
5075 // in the same direction
5076 if ( $.mobile.activePage && !$.mobile.activePage.is( ".ui-dialog" ) ) {
5077 //determine if we're heading forward or backward and continue accordingly past
5078 //the current dialog
5079 if( data.direction === "back" ) {
5080 $.mobile.back();
5081 } else {
5082 window.history.forward();
5083 }
5084
5085 // prevent changePage call
5086 return;
5087 } else {
5088 // if the current active page is a dialog and we're navigating
5089 // to a dialog use the dialog objected saved in the stack
5090 to = data.pageUrl;
5091 var active = $.mobile.urlHistory.getActive();
5092
5093 // make sure to set the role, transition and reversal
5094 // as most of this is lost by the domCache cleaning
5095 $.extend( changePageOptions, {
5096 role: active.role,
5097 transition: active.transition,
5098 reverse: data.direction === "back"
5099 });
5100 }
5101 }
5102
5103 //if to is defined, load it
5104 if ( to ) {
5105 // At this point, 'to' can be one of 3 things, a cached page element from
5106 // a history stack entry, an id, or site-relative/absolute URL. If 'to' is
5107 // an id, we need to resolve it against the documentBase, not the location.href,
5108 // since the hashchange could've been the result of a forward/backward navigation
5109 // that crosses from an external page/dialog to an internal page/dialog.
5110 to = !path.isPath( to ) ? ( path.makeUrlAbsolute( '#' + to, documentBase ) ) : to;
5111
5112 // If we're about to go to an initial URL that contains a reference to a non-existent
5113 // internal page, go to the first page instead. We know that the initial hash refers to a
5114 // non-existent page, because the initial hash did not end up in the initial urlHistory entry
5115 if ( to === path.makeUrlAbsolute( '#' + urlHistory.initialDst, documentBase ) &&
5116 urlHistory.stack.length && urlHistory.stack[0].url !== urlHistory.initialDst.replace( dialogHashKey, "" ) ) {
5117 to = $.mobile.firstPage;
5118 }
5119
5120 $.mobile.changePage( to, changePageOptions );
5121 } else {
5122
5123 //there's no hash, go to the first page in the dom
5124 $.mobile.changePage( $.mobile.firstPage, changePageOptions );
5125 }
5126 };
5127
5128 // TODO roll the logic here into the handleHashChange method
5129 $window.bind( "navigate", function( e, data ) {
5130 var url;
5131
5132 if ( e.originalEvent && e.originalEvent.isDefaultPrevented() ) {
5133 return;
5134 }
5135
5136 url = $.event.special.navigate.originalEventName.indexOf( "hashchange" ) > -1 ? data.state.hash : data.state.url;
5137
5138 if( !url ) {
5139 url = $.mobile.path.parseLocation().hash;
5140 }
5141
5142 if( !url || url === "#" || url.indexOf( "#" + $.mobile.path.uiStateKey ) === 0 ){
5143 url = location.href;
5144 }
5145
5146 $.mobile._handleHashChange( url, data.state );
5147 });
5148
5149 //set page min-heights to be device specific
5150 $.mobile.document.bind( "pageshow", $.mobile.resetActivePageHeight );
5151 $.mobile.window.bind( "throttledresize", $.mobile.resetActivePageHeight );
5152
5153 };//navreadyDeferred done callback
5154
5155 $( function() { domreadyDeferred.resolve(); } );
5156
5157 $.when( domreadyDeferred, $.mobile.navreadyDeferred ).done( function() { $.mobile._registerInternalEvents(); } );
5158})( jQuery );
5159
5160/*
5161* fallback transition for flip in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5162*/
5163
5164(function( $, window, undefined ) {
5165
5166$.mobile.transitionFallbacks.flip = "fade";
5167
5168})( jQuery, this );
5169/*
5170* fallback transition for flow in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5171*/
5172
5173(function( $, window, undefined ) {
5174
5175$.mobile.transitionFallbacks.flow = "fade";
5176
5177})( jQuery, this );
5178/*
5179* fallback transition for pop in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5180*/
5181
5182(function( $, window, undefined ) {
5183
5184$.mobile.transitionFallbacks.pop = "fade";
5185
5186})( jQuery, this );
5187/*
5188* fallback transition for slide in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5189*/
5190
5191(function( $, window, undefined ) {
5192
5193// Use the simultaneous transitions handler for slide transitions
5194$.mobile.transitionHandlers.slide = $.mobile.transitionHandlers.simultaneous;
5195
5196// Set the slide transitions's fallback to "fade"
5197$.mobile.transitionFallbacks.slide = "fade";
5198
5199})( jQuery, this );
5200/*
5201* fallback transition for slidedown in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5202*/
5203
5204(function( $, window, undefined ) {
5205
5206$.mobile.transitionFallbacks.slidedown = "fade";
5207
5208})( jQuery, this );
5209/*
5210* fallback transition for slidefade in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5211*/
5212
5213(function( $, window, undefined ) {
5214
5215// Set the slide transitions's fallback to "fade"
5216$.mobile.transitionFallbacks.slidefade = "fade";
5217
5218})( jQuery, this );
5219/*
5220* fallback transition for slideup in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5221*/
5222
5223(function( $, window, undefined ) {
5224
5225$.mobile.transitionFallbacks.slideup = "fade";
5226
5227})( jQuery, this );
5228/*
5229* fallback transition for turn in non-3D supporting browsers (which tend to handle complex transitions poorly in general
5230*/
5231
5232(function( $, window, undefined ) {
5233
5234$.mobile.transitionFallbacks.turn = "fade";
5235
5236})( jQuery, this );
5237
5238(function( $, undefined ) {
5239
5240$.mobile.page.prototype.options.degradeInputs = {
5241 color: false,
5242 date: false,
5243 datetime: false,
5244 "datetime-local": false,
5245 email: false,
5246 month: false,
5247 number: false,
5248 range: "number",
5249 search: "text",
5250 tel: false,
5251 time: false,
5252 url: false,
5253 week: false
5254};
5255
5256
5257//auto self-init widgets
5258$.mobile.document.bind( "pagecreate create", function( e ) {
5259
5260 var page = $.mobile.closestPageData( $( e.target ) ), options;
5261
5262 if ( !page ) {
5263 return;
5264 }
5265
5266 options = page.options;
5267
5268 // degrade inputs to avoid poorly implemented native functionality
5269 $( e.target ).find( "input" ).not( page.keepNativeSelector() ).each(function() {
5270 var $this = $( this ),
5271 type = this.getAttribute( "type" ),
5272 optType = options.degradeInputs[ type ] || "text";
5273
5274 if ( options.degradeInputs[ type ] ) {
5275 var html = $( "<div>" ).html( $this.clone() ).html(),
5276 // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
5277 hasType = html.indexOf( " type=" ) > -1,
5278 findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/,
5279 repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );
5280
5281 $this.replaceWith( html.replace( findstr, repstr ) );
5282 }
5283 });
5284
5285});
5286
5287})( jQuery );
5288
5289(function( $, window, undefined ) {
5290
5291$.widget( "mobile.dialog", $.mobile.widget, {
5292 options: {
5293 closeBtn: "left",
5294 closeBtnText: "Close",
5295 overlayTheme: "a",
5296 corners: true,
5297 initSelector: ":jqmData(role='dialog')"
5298 },
5299
5300 // Override the theme set by the page plugin on pageshow
5301 _handlePageBeforeShow: function() {
5302 this._isCloseable = true;
5303 if ( this.options.overlayTheme ) {
5304 this.element
5305 .page( "removeContainerBackground" )
5306 .page( "setContainerBackground", this.options.overlayTheme );
5307 }
5308 },
5309
5310 _handlePageBeforeHide: function() {
5311 this._isCloseable = false;
5312 },
5313
5314 _create: function() {
5315 var self = this,
5316 $el = this.element,
5317 cornerClass = !!this.options.corners ? " ui-corner-all" : "",
5318 dialogWrap = $( "<div/>", {
5319 "role" : "dialog",
5320 "class" : "ui-dialog-contain ui-overlay-shadow" + cornerClass
5321 });
5322
5323 $el.addClass( "ui-dialog ui-overlay-" + this.options.overlayTheme );
5324
5325 // Class the markup for dialog styling
5326 // Set aria role
5327 $el.wrapInner( dialogWrap );
5328
5329 /* bind events
5330 - clicks and submits should use the closing transition that the dialog opened with
5331 unless a data-transition is specified on the link/form
5332 - if the click was on the close button, or the link has a data-rel="back" it'll go back in history naturally
5333 */
5334 $el.bind( "vclick submit", function( event ) {
5335 var $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" ),
5336 active;
5337
5338 if ( $target.length && !$target.jqmData( "transition" ) ) {
5339
5340 active = $.mobile.urlHistory.getActive() || {};
5341
5342 $target.attr( "data-" + $.mobile.ns + "transition", ( active.transition || $.mobile.defaultDialogTransition ) )
5343 .attr( "data-" + $.mobile.ns + "direction", "reverse" );
5344 }
5345 });
5346
5347 this._on( $el, {
5348 pagebeforeshow: "_handlePageBeforeShow",
5349 pagebeforehide: "_handlePageBeforeHide"
5350 });
5351
5352 $.extend( this, {
5353 _createComplete: false
5354 });
5355
5356 this._setCloseBtn( this.options.closeBtn );
5357 },
5358
5359 _setCloseBtn: function( value ) {
5360 var self = this, btn, location;
5361
5362 if ( this._headerCloseButton ) {
5363 this._headerCloseButton.remove();
5364 this._headerCloseButton = null;
5365 }
5366 if ( value !== "none" ) {
5367 // Sanitize value
5368 location = ( value === "left" ? "left" : "right" );
5369 btn = $( "<a href='#' class='ui-btn-" + location + "' data-" + $.mobile.ns + "icon='delete' data-" + $.mobile.ns + "iconpos='notext'>"+ this.options.closeBtnText + "</a>" );
5370 this.element.children().find( ":jqmData(role='header')" ).first().prepend( btn );
5371 if ( this._createComplete && $.fn.buttonMarkup ) {
5372 btn.buttonMarkup();
5373 }
5374 this._createComplete = true;
5375
5376 // this must be an anonymous function so that select menu dialogs can replace
5377 // the close method. This is a change from previously just defining data-rel=back
5378 // on the button and letting nav handle it
5379 //
5380 // Use click rather than vclick in order to prevent the possibility of unintentionally
5381 // reopening the dialog if the dialog opening item was directly under the close button.
5382 btn.bind( "click", function() {
5383 self.close();
5384 });
5385
5386 this._headerCloseButton = btn;
5387 }
5388 },
5389
5390 _setOption: function( key, value ) {
5391 if ( key === "closeBtn" ) {
5392 this._setCloseBtn( value );
5393 }
5394 this._super( key, value );
5395 },
5396
5397 // Close method goes back in history
5398 close: function() {
5399 var idx, dst, hist = $.mobile.navigate.history;
5400
5401 if ( this._isCloseable ) {
5402 this._isCloseable = false;
5403 // If the hash listening is enabled and there is at least one preceding history
5404 // entry it's ok to go back. Initial pages with the dialog hash state are an example
5405 // where the stack check is necessary
5406 if ( $.mobile.hashListeningEnabled && hist.activeIndex > 0 ) {
5407 $.mobile.back();
5408 } else {
5409 idx = Math.max( 0, hist.activeIndex - 1 );
5410 dst = hist.stack[ idx ].pageUrl || hist.stack[ idx ].url;
5411 hist.previousIndex = hist.activeIndex;
5412 hist.activeIndex = idx;
5413 if ( !$.mobile.path.isPath( dst ) ) {
5414 dst = $.mobile.path.makeUrlAbsolute( "#" + dst );
5415 }
5416
5417 $.mobile.changePage( dst, { direction: "back", changeHash: false, fromHashChange: true } );
5418 }
5419 }
5420 }
5421});
5422
5423//auto self-init widgets
5424$.mobile.document.delegate( $.mobile.dialog.prototype.options.initSelector, "pagecreate", function() {
5425 $.mobile.dialog.prototype.enhance( this );
5426});
5427
5428})( jQuery, this );
5429
5430(function( $, undefined ) {
5431
5432$.mobile.page.prototype.options.backBtnText = "Back";
5433$.mobile.page.prototype.options.addBackBtn = false;
5434$.mobile.page.prototype.options.backBtnTheme = null;
5435$.mobile.page.prototype.options.headerTheme = "a";
5436$.mobile.page.prototype.options.footerTheme = "a";
5437$.mobile.page.prototype.options.contentTheme = null;
5438
5439// NOTE bind used to force this binding to run before the buttonMarkup binding
5440// which expects .ui-footer top be applied in its gigantic selector
5441// TODO remove the buttonMarkup giant selector and move it to the various modules
5442// on which it depends
5443$.mobile.document.bind( "pagecreate", function( e ) {
5444 var $page = $( e.target ),
5445 o = $page.data( "mobile-page" ).options,
5446 pageRole = $page.jqmData( "role" ),
5447 pageTheme = o.theme;
5448
5449 $( ":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')", $page )
5450 .jqmEnhanceable()
5451 .each(function() {
5452
5453 var $this = $( this ),
5454 role = $this.jqmData( "role" ),
5455 theme = $this.jqmData( "theme" ),
5456 contentTheme = theme || o.contentTheme || ( pageRole === "dialog" && pageTheme ),
5457 $headeranchors,
5458 leftbtn,
5459 rightbtn,
5460 backBtn;
5461
5462 $this.addClass( "ui-" + role );
5463
5464 //apply theming and markup modifications to page,header,content,footer
5465 if ( role === "header" || role === "footer" ) {
5466
5467 var thisTheme = theme || ( role === "header" ? o.headerTheme : o.footerTheme ) || pageTheme;
5468
5469 $this
5470 //add theme class
5471 .addClass( "ui-bar-" + thisTheme )
5472 // Add ARIA role
5473 .attr( "role", role === "header" ? "banner" : "contentinfo" );
5474
5475 if ( role === "header") {
5476 // Right,left buttons
5477 $headeranchors = $this.children( "a, button" );
5478 leftbtn = $headeranchors.hasClass( "ui-btn-left" );
5479 rightbtn = $headeranchors.hasClass( "ui-btn-right" );
5480
5481 leftbtn = leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
5482
5483 rightbtn = rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
5484 }
5485
5486 // Auto-add back btn on pages beyond first view
5487 if ( o.addBackBtn &&
5488 role === "header" &&
5489 $( ".ui-page" ).length > 1 &&
5490 $page.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) &&
5491 !leftbtn ) {
5492
5493 backBtn = $( "<a href='javascript:void(0);' class='ui-btn-left' data-"+ $.mobile.ns +"rel='back' data-"+ $.mobile.ns +"icon='arrow-l'>"+ o.backBtnText +"</a>" )
5494 // If theme is provided, override default inheritance
5495 .attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme || thisTheme )
5496 .prependTo( $this );
5497 }
5498
5499 // Page title
5500 $this.children( "h1, h2, h3, h4, h5, h6" )
5501 .addClass( "ui-title" )
5502 // Regardless of h element number in src, it becomes h1 for the enhanced page
5503 .attr({
5504 "role": "heading",
5505 "aria-level": "1"
5506 });
5507
5508 } else if ( role === "content" ) {
5509 if ( contentTheme ) {
5510 $this.addClass( "ui-body-" + ( contentTheme ) );
5511 }
5512
5513 // Add ARIA role
5514 $this.attr( "role", "main" );
5515 }
5516 });
5517});
5518
5519})( jQuery );
5520
5521(function( $, undefined ) {
5522
5523// This function calls getAttribute, which should be safe for data-* attributes
5524var getAttrFixed = function( e, key ) {
5525 var value = e.getAttribute( key );
5526
5527 return value === "true" ? true :
5528 value === "false" ? false :
5529 value === null ? undefined : value;
5530};
5531
5532$.fn.buttonMarkup = function( options ) {
5533 var $workingSet = this,
5534 nsKey = "data-" + $.mobile.ns,
5535 key;
5536
5537 // Enforce options to be of type string
5538 options = ( options && ( $.type( options ) === "object" ) )? options : {};
5539 for ( var i = 0; i < $workingSet.length; i++ ) {
5540 var el = $workingSet.eq( i ),
5541 e = el[ 0 ],
5542 o = $.extend( {}, $.fn.buttonMarkup.defaults, {
5543 icon: options.icon !== undefined ? options.icon : getAttrFixed( e, nsKey + "icon" ),
5544 iconpos: options.iconpos !== undefined ? options.iconpos : getAttrFixed( e, nsKey + "iconpos" ),
5545 theme: options.theme !== undefined ? options.theme : getAttrFixed( e, nsKey + "theme" ) || $.mobile.getInheritedTheme( el, "c" ),
5546 inline: options.inline !== undefined ? options.inline : getAttrFixed( e, nsKey + "inline" ),
5547 shadow: options.shadow !== undefined ? options.shadow : getAttrFixed( e, nsKey + "shadow" ),
5548 corners: options.corners !== undefined ? options.corners : getAttrFixed( e, nsKey + "corners" ),
5549 iconshadow: options.iconshadow !== undefined ? options.iconshadow : getAttrFixed( e, nsKey + "iconshadow" ),
5550 mini: options.mini !== undefined ? options.mini : getAttrFixed( e, nsKey + "mini" )
5551 }, options ),
5552
5553 // Classes Defined
5554 innerClass = "ui-btn-inner",
5555 textClass = "ui-btn-text",
5556 buttonClass, iconClass,
5557 hover = false,
5558 state = "up",
5559 // Button inner markup
5560 buttonInner,
5561 buttonText,
5562 buttonIcon,
5563 buttonElements;
5564
5565 for ( key in o ) {
5566 if ( o[ key ] === undefined || o[ key ] === null ) {
5567 el.removeAttr( nsKey + key );
5568 } else {
5569 e.setAttribute( nsKey + key, o[ key ] );
5570 }
5571 }
5572
5573 // Check if this element is already enhanced
5574 buttonElements = $.data( ( ( e.tagName === "INPUT" || e.tagName === "BUTTON" ) ? e.parentNode : e ), "buttonElements" );
5575
5576 if ( buttonElements ) {
5577 e = buttonElements.outer;
5578 el = $( e );
5579 buttonInner = buttonElements.inner;
5580 buttonText = buttonElements.text;
5581 // We will recreate this icon below
5582 $( buttonElements.icon ).remove();
5583 buttonElements.icon = null;
5584 hover = buttonElements.hover;
5585 state = buttonElements.state;
5586 }
5587 else {
5588 buttonInner = document.createElement( o.wrapperEls );
5589 buttonText = document.createElement( o.wrapperEls );
5590 }
5591 buttonIcon = o.icon ? document.createElement( "span" ) : null;
5592
5593 if ( attachEvents && !buttonElements ) {
5594 attachEvents();
5595 }
5596
5597 // if not, try to find closest theme container
5598 if ( !o.theme ) {
5599 o.theme = $.mobile.getInheritedTheme( el, "c" );
5600 }
5601
5602 buttonClass = "ui-btn ";
5603 buttonClass += ( hover ? "ui-btn-hover-" + o.theme : "" );
5604 buttonClass += ( state ? " ui-btn-" + state + "-" + o.theme : "" );
5605 buttonClass += o.shadow ? " ui-shadow" : "";
5606 buttonClass += o.corners ? " ui-btn-corner-all" : "";
5607
5608 if ( o.mini !== undefined ) {
5609 // Used to control styling in headers/footers, where buttons default to `mini` style.
5610 buttonClass += o.mini === true ? " ui-mini" : " ui-fullsize";
5611 }
5612
5613 if ( o.inline !== undefined ) {
5614 // Used to control styling in headers/footers, where buttons default to `inline` style.
5615 buttonClass += o.inline === true ? " ui-btn-inline" : " ui-btn-block";
5616 }
5617
5618 if ( o.icon ) {
5619 o.icon = "ui-icon-" + o.icon;
5620 o.iconpos = o.iconpos || "left";
5621
5622 iconClass = "ui-icon " + o.icon;
5623
5624 if ( o.iconshadow ) {
5625 iconClass += " ui-icon-shadow";
5626 }
5627 }
5628
5629 if ( o.iconpos ) {
5630 buttonClass += " ui-btn-icon-" + o.iconpos;
5631
5632 if ( o.iconpos === "notext" && !el.attr( "title" ) ) {
5633 el.attr( "title", el.getEncodedText() );
5634 }
5635 }
5636
5637 if ( buttonElements ) {
5638 el.removeClass( buttonElements.bcls || "" );
5639 }
5640 el.removeClass( "ui-link" ).addClass( buttonClass );
5641
5642 buttonInner.className = innerClass;
5643 buttonText.className = textClass;
5644 if ( !buttonElements ) {
5645 buttonInner.appendChild( buttonText );
5646 }
5647 if ( buttonIcon ) {
5648 buttonIcon.className = iconClass;
5649 if ( !( buttonElements && buttonElements.icon ) ) {
5650 buttonIcon.innerHTML = "&#160;";
5651 buttonInner.appendChild( buttonIcon );
5652 }
5653 }
5654
5655 while ( e.firstChild && !buttonElements ) {
5656 buttonText.appendChild( e.firstChild );
5657 }
5658
5659 if ( !buttonElements ) {
5660 e.appendChild( buttonInner );
5661 }
5662
5663 // Assign a structure containing the elements of this button to the elements of this button. This
5664 // will allow us to recognize this as an already-enhanced button in future calls to buttonMarkup().
5665 buttonElements = {
5666 hover : hover,
5667 state : state,
5668 bcls : buttonClass,
5669 outer : e,
5670 inner : buttonInner,
5671 text : buttonText,
5672 icon : buttonIcon
5673 };
5674
5675 $.data( e, 'buttonElements', buttonElements );
5676 $.data( buttonInner, 'buttonElements', buttonElements );
5677 $.data( buttonText, 'buttonElements', buttonElements );
5678 if ( buttonIcon ) {
5679 $.data( buttonIcon, 'buttonElements', buttonElements );
5680 }
5681 }
5682
5683 return this;
5684};
5685
5686$.fn.buttonMarkup.defaults = {
5687 corners: true,
5688 shadow: true,
5689 iconshadow: true,
5690 wrapperEls: "span"
5691};
5692
5693function closestEnabledButton( element ) {
5694 var cname;
5695
5696 while ( element ) {
5697 // Note that we check for typeof className below because the element we
5698 // handed could be in an SVG DOM where className on SVG elements is defined to
5699 // be of a different type (SVGAnimatedString). We only operate on HTML DOM
5700 // elements, so we look for plain "string".
5701 cname = ( typeof element.className === 'string' ) && ( element.className + ' ' );
5702 if ( cname && cname.indexOf( "ui-btn " ) > -1 && cname.indexOf( "ui-disabled " ) < 0 ) {
5703 break;
5704 }
5705
5706 element = element.parentNode;
5707 }
5708
5709 return element;
5710}
5711
5712function updateButtonClass( $btn, classToRemove, classToAdd, hover, state ) {
5713 var buttonElements = $.data( $btn[ 0 ], "buttonElements" );
5714 $btn.removeClass( classToRemove ).addClass( classToAdd );
5715 if ( buttonElements ) {
5716 buttonElements.bcls = $( document.createElement( "div" ) )
5717 .addClass( buttonElements.bcls + " " + classToAdd )
5718 .removeClass( classToRemove )
5719 .attr( "class" );
5720 if ( hover !== undefined ) {
5721 buttonElements.hover = hover;
5722 }
5723 buttonElements.state = state;
5724 }
5725}
5726
5727var attachEvents = function() {
5728 var hoverDelay = $.mobile.buttonMarkup.hoverDelay, hov, foc;
5729
5730 $.mobile.document.bind( {
5731 "vmousedown vmousecancel vmouseup vmouseover vmouseout focus blur scrollstart": function( event ) {
5732 var theme,
5733 $btn = $( closestEnabledButton( event.target ) ),
5734 isTouchEvent = event.originalEvent && /^touch/.test( event.originalEvent.type ),
5735 evt = event.type;
5736
5737 if ( $btn.length ) {
5738 theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
5739
5740 if ( evt === "vmousedown" ) {
5741 if ( isTouchEvent ) {
5742 // Use a short delay to determine if the user is scrolling before highlighting
5743 hov = setTimeout( function() {
5744 updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
5745 }, hoverDelay );
5746 } else {
5747 updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
5748 }
5749 } else if ( evt === "vmousecancel" || evt === "vmouseup" ) {
5750 updateButtonClass( $btn, "ui-btn-down-" + theme, "ui-btn-up-" + theme, undefined, "up" );
5751 } else if ( evt === "vmouseover" || evt === "focus" ) {
5752 if ( isTouchEvent ) {
5753 // Use a short delay to determine if the user is scrolling before highlighting
5754 foc = setTimeout( function() {
5755 updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
5756 }, hoverDelay );
5757 } else {
5758 updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
5759 }
5760 } else if ( evt === "vmouseout" || evt === "blur" || evt === "scrollstart" ) {
5761 updateButtonClass( $btn, "ui-btn-hover-" + theme + " ui-btn-down-" + theme, "ui-btn-up-" + theme, false, "up" );
5762 if ( hov ) {
5763 clearTimeout( hov );
5764 }
5765 if ( foc ) {
5766 clearTimeout( foc );
5767 }
5768 }
5769 }
5770 },
5771 "focusin focus": function( event ) {
5772 $( closestEnabledButton( event.target ) ).addClass( $.mobile.focusClass );
5773 },
5774 "focusout blur": function( event ) {
5775 $( closestEnabledButton( event.target ) ).removeClass( $.mobile.focusClass );
5776 }
5777 });
5778
5779 attachEvents = null;
5780};
5781
5782//links in bars, or those with data-role become buttons
5783//auto self-init widgets
5784$.mobile.document.bind( "pagecreate create", function( e ) {
5785
5786 $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
5787 .jqmEnhanceable()
5788 .not( "button, input, .ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
5789 .buttonMarkup();
5790});
5791
5792})( jQuery );
5793
5794
5795(function( $, undefined ) {
5796
5797$.widget( "mobile.collapsible", $.mobile.widget, {
5798 options: {
5799 expandCueText: " click to expand contents",
5800 collapseCueText: " click to collapse contents",
5801 collapsed: true,
5802 heading: "h1,h2,h3,h4,h5,h6,legend",
5803 collapsedIcon: "plus",
5804 expandedIcon: "minus",
5805 iconpos: "left",
5806 theme: null,
5807 contentTheme: null,
5808 inset: true,
5809 corners: true,
5810 mini: false,
5811 initSelector: ":jqmData(role='collapsible')"
5812 },
5813 _create: function() {
5814
5815 var $el = this.element,
5816 o = this.options,
5817 collapsible = $el.addClass( "ui-collapsible" ),
5818 collapsibleHeading = $el.children( o.heading ).first(),
5819 collapsibleContent = collapsible.wrapInner( "<div class='ui-collapsible-content'></div>" ).children( ".ui-collapsible-content" ),
5820 collapsibleSet = $el.closest( ":jqmData(role='collapsible-set')" ).addClass( "ui-collapsible-set" ),
5821 collapsibleClasses = "";
5822
5823 // Replace collapsibleHeading if it's a legend
5824 if ( collapsibleHeading.is( "legend" ) ) {
5825 collapsibleHeading = $( "<div role='heading'>"+ collapsibleHeading.html() +"</div>" ).insertBefore( collapsibleHeading );
5826 collapsibleHeading.next().remove();
5827 }
5828
5829 // If we are in a collapsible set
5830 if ( collapsibleSet.length ) {
5831 // Inherit the theme from collapsible-set
5832 if ( !o.theme ) {
5833 o.theme = collapsibleSet.jqmData( "theme" ) || $.mobile.getInheritedTheme( collapsibleSet, "c" );
5834 }
5835 // Inherit the content-theme from collapsible-set
5836 if ( !o.contentTheme ) {
5837 o.contentTheme = collapsibleSet.jqmData( "content-theme" );
5838 }
5839
5840 // Get the preference for collapsed icon in the set, but override with data- attribute on the individual collapsible
5841 o.collapsedIcon = $el.jqmData( "collapsed-icon" ) || collapsibleSet.jqmData( "collapsed-icon" ) || o.collapsedIcon;
5842
5843 // Get the preference for expanded icon in the set, but override with data- attribute on the individual collapsible
5844 o.expandedIcon = $el.jqmData( "expanded-icon" ) || collapsibleSet.jqmData( "expanded-icon" ) || o.expandedIcon;
5845
5846 // Gets the preference icon position in the set, but override with data- attribute on the individual collapsible
5847 o.iconpos = $el.jqmData( "iconpos" ) || collapsibleSet.jqmData( "iconpos" ) || o.iconpos;
5848
5849 // Inherit the preference for inset from collapsible-set or set the default value to ensure equalty within a set
5850 if ( collapsibleSet.jqmData( "inset" ) !== undefined ) {
5851 o.inset = collapsibleSet.jqmData( "inset" );
5852 } else {
5853 o.inset = true;
5854 }
5855 // Set corners for individual collapsibles to false when in a collapsible-set
5856 o.corners = false;
5857 // Gets the preference for mini in the set
5858 if ( !o.mini ) {
5859 o.mini = collapsibleSet.jqmData( "mini" );
5860 }
5861 } else {
5862 // get inherited theme if not a set and no theme has been set
5863 if ( !o.theme ) {
5864 o.theme = $.mobile.getInheritedTheme( $el, "c" );
5865 }
5866 }
5867
5868 if ( !!o.inset ) {
5869 collapsibleClasses += " ui-collapsible-inset";
5870 if ( !!o.corners ) {
5871 collapsibleClasses += " ui-corner-all" ;
5872 }
5873 }
5874 if ( o.contentTheme ) {
5875 collapsibleClasses += " ui-collapsible-themed-content";
5876 collapsibleContent.addClass( "ui-body-" + o.contentTheme );
5877 }
5878 if ( collapsibleClasses !== "" ) {
5879 collapsible.addClass( collapsibleClasses );
5880 }
5881
5882 collapsibleHeading
5883 //drop heading in before content
5884 .insertBefore( collapsibleContent )
5885 //modify markup & attributes
5886 .addClass( "ui-collapsible-heading" )
5887 .append( "<span class='ui-collapsible-heading-status'></span>" )
5888 .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
5889 .find( "a" )
5890 .first()
5891 .buttonMarkup({
5892 shadow: false,
5893 corners: false,
5894 iconpos: o.iconpos,
5895 icon: o.collapsedIcon,
5896 mini: o.mini,
5897 theme: o.theme
5898 });
5899
5900 //events
5901 collapsible
5902 .bind( "expand collapse", function( event ) {
5903 if ( !event.isDefaultPrevented() ) {
5904 var $this = $( this ),
5905 isCollapse = ( event.type === "collapse" );
5906
5907 event.preventDefault();
5908
5909 collapsibleHeading
5910 .toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
5911 .find( ".ui-collapsible-heading-status" )
5912 .text( isCollapse ? o.expandCueText : o.collapseCueText )
5913 .end()
5914 .find( ".ui-icon" )
5915 .toggleClass( "ui-icon-" + o.expandedIcon, !isCollapse )
5916 // logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
5917 .toggleClass( "ui-icon-" + o.collapsedIcon, ( isCollapse || o.expandedIcon === o.collapsedIcon ) )
5918 .end()
5919 .find( "a" ).first().removeClass( $.mobile.activeBtnClass );
5920
5921 $this.toggleClass( "ui-collapsible-collapsed", isCollapse );
5922 collapsibleContent.toggleClass( "ui-collapsible-content-collapsed", isCollapse ).attr( "aria-hidden", isCollapse );
5923
5924 collapsibleContent.trigger( "updatelayout" );
5925 }
5926 })
5927 .trigger( o.collapsed ? "collapse" : "expand" );
5928
5929 collapsibleHeading
5930 .bind( "tap", function( event ) {
5931 collapsibleHeading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
5932 })
5933 .bind( "click", function( event ) {
5934
5935 var type = collapsibleHeading.is( ".ui-collapsible-heading-collapsed" ) ? "expand" : "collapse";
5936
5937 collapsible.trigger( type );
5938
5939 event.preventDefault();
5940 event.stopPropagation();
5941 });
5942 }
5943});
5944
5945//auto self-init widgets
5946$.mobile.document.bind( "pagecreate create", function( e ) {
5947 $.mobile.collapsible.prototype.enhanceWithin( e.target );
5948});
5949
5950})( jQuery );
5951
5952(function( $, undefined ) {
5953
5954$.mobile.behaviors.addFirstLastClasses = {
5955 _getVisibles: function( $els, create ) {
5956 var visibles;
5957
5958 if ( create ) {
5959 visibles = $els.not( ".ui-screen-hidden" );
5960 } else {
5961 visibles = $els.filter( ":visible" );
5962 if ( visibles.length === 0 ) {
5963 visibles = $els.not( ".ui-screen-hidden" );
5964 }
5965 }
5966
5967 return visibles;
5968 },
5969
5970 _addFirstLastClasses: function( $els, $visibles, create ) {
5971 $els.removeClass( "ui-first-child ui-last-child" );
5972 $visibles.eq( 0 ).addClass( "ui-first-child" ).end().last().addClass( "ui-last-child" );
5973 if ( !create ) {
5974 this.element.trigger( "updatelayout" );
5975 }
5976 }
5977};
5978
5979})( jQuery );
5980
5981(function( $, undefined ) {
5982
5983$.widget( "mobile.collapsibleset", $.mobile.widget, $.extend( {
5984 options: {
5985 initSelector: ":jqmData(role='collapsible-set')"
5986 },
5987 _create: function() {
5988 var $el = this.element.addClass( "ui-collapsible-set" ),
5989 o = this.options;
5990
5991 // Inherit the theme from collapsible-set
5992 if ( !o.theme ) {
5993 o.theme = $.mobile.getInheritedTheme( $el, "c" );
5994 }
5995 // Inherit the content-theme from collapsible-set
5996 if ( !o.contentTheme ) {
5997 o.contentTheme = $el.jqmData( "content-theme" );
5998 }
5999 // Inherit the corner styling from collapsible-set
6000 if ( !o.corners ) {
6001 o.corners = $el.jqmData( "corners" );
6002 }
6003
6004 if ( $el.jqmData( "inset" ) !== undefined ) {
6005 o.inset = $el.jqmData( "inset" );
6006 }
6007 o.inset = o.inset !== undefined ? o.inset : true;
6008 o.corners = o.corners !== undefined ? o.corners : true;
6009
6010 if ( !!o.corners && !!o.inset ) {
6011 $el.addClass( "ui-corner-all" );
6012 }
6013
6014 // Initialize the collapsible set if it's not already initialized
6015 if ( !$el.jqmData( "collapsiblebound" ) ) {
6016 $el
6017 .jqmData( "collapsiblebound", true )
6018 .bind( "expand", function( event ) {
6019 var closestCollapsible = $( event.target )
6020 .closest( ".ui-collapsible" );
6021 if ( closestCollapsible.parent().is( ":jqmData(role='collapsible-set')" ) ) {
6022 closestCollapsible
6023 .siblings( ".ui-collapsible" )
6024 .trigger( "collapse" );
6025 }
6026 });
6027 }
6028 },
6029
6030 _init: function() {
6031 var $el = this.element,
6032 collapsiblesInSet = $el.children( ":jqmData(role='collapsible')" ),
6033 expanded = collapsiblesInSet.filter( ":jqmData(collapsed='false')" );
6034 this._refresh( "true" );
6035
6036 // Because the corners are handled by the collapsible itself and the default state is collapsed
6037 // That was causing https://github.com/jquery/jquery-mobile/issues/4116
6038 expanded.trigger( "expand" );
6039 },
6040
6041 _refresh: function( create ) {
6042 var collapsiblesInSet = this.element.children( ":jqmData(role='collapsible')" );
6043
6044 $.mobile.collapsible.prototype.enhance( collapsiblesInSet.not( ".ui-collapsible" ) );
6045
6046 this._addFirstLastClasses( collapsiblesInSet, this._getVisibles( collapsiblesInSet, create ), create );
6047 },
6048
6049 refresh: function() {
6050 this._refresh( false );
6051 }
6052}, $.mobile.behaviors.addFirstLastClasses ) );
6053
6054//auto self-init widgets
6055$.mobile.document.bind( "pagecreate create", function( e ) {
6056 $.mobile.collapsibleset.prototype.enhanceWithin( e.target );
6057});
6058
6059})( jQuery );
6060
6061(function( $, undefined ) {
6062
6063// filter function removes whitespace between label and form element so we can use inline-block (nodeType 3 = text)
6064$.fn.fieldcontain = function( options ) {
6065 return this
6066 .addClass( "ui-field-contain ui-body ui-br" )
6067 .contents().filter( function() {
6068 return ( this.nodeType === 3 && !/\S/.test( this.nodeValue ) );
6069 }).remove();
6070};
6071
6072//auto self-init widgets
6073$( document ).bind( "pagecreate create", function( e ) {
6074 $( ":jqmData(role='fieldcontain')", e.target ).jqmEnhanceable().fieldcontain();
6075});
6076
6077})( jQuery );
6078
6079(function( $, undefined ) {
6080
6081$.fn.grid = function( options ) {
6082 return this.each(function() {
6083
6084 var $this = $( this ),
6085 o = $.extend({
6086 grid: null
6087 }, options ),
6088 $kids = $this.children(),
6089 gridCols = { solo:1, a:2, b:3, c:4, d:5 },
6090 grid = o.grid,
6091 iterator;
6092
6093 if ( !grid ) {
6094 if ( $kids.length <= 5 ) {
6095 for ( var letter in gridCols ) {
6096 if ( gridCols[ letter ] === $kids.length ) {
6097 grid = letter;
6098 }
6099 }
6100 } else {
6101 grid = "a";
6102 $this.addClass( "ui-grid-duo" );
6103 }
6104 }
6105 iterator = gridCols[grid];
6106
6107 $this.addClass( "ui-grid-" + grid );
6108
6109 $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
6110
6111 if ( iterator > 1 ) {
6112 $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
6113 }
6114 if ( iterator > 2 ) {
6115 $kids.filter( ":nth-child(" + iterator + "n+3)" ).addClass( "ui-block-c" );
6116 }
6117 if ( iterator > 3 ) {
6118 $kids.filter( ":nth-child(" + iterator + "n+4)" ).addClass( "ui-block-d" );
6119 }
6120 if ( iterator > 4 ) {
6121 $kids.filter( ":nth-child(" + iterator + "n+5)" ).addClass( "ui-block-e" );
6122 }
6123 });
6124};
6125})( jQuery );
6126
6127(function( $, undefined ) {
6128
6129$.widget( "mobile.navbar", $.mobile.widget, {
6130 options: {
6131 iconpos: "top",
6132 grid: null,
6133 initSelector: ":jqmData(role='navbar')"
6134 },
6135
6136 _create: function() {
6137
6138 var $navbar = this.element,
6139 $navbtns = $navbar.find( "a" ),
6140 iconpos = $navbtns.filter( ":jqmData(icon)" ).length ?
6141 this.options.iconpos : undefined;
6142
6143 $navbar.addClass( "ui-navbar ui-mini" )
6144 .attr( "role", "navigation" )
6145 .find( "ul" )
6146 .jqmEnhanceable()
6147 .grid({ grid: this.options.grid });
6148
6149 $navbtns.buttonMarkup({
6150 corners: false,
6151 shadow: false,
6152 inline: true,
6153 iconpos: iconpos
6154 });
6155
6156 $navbar.delegate( "a", "vclick", function( event ) {
6157 // ui-btn-inner is returned as target
6158 var target = $( event.target ).is( "a" ) ? $( this ) : $( this ).parent( "a" );
6159
6160 if ( !target.is( ".ui-disabled, .ui-btn-active" ) ) {
6161 $navbtns.removeClass( $.mobile.activeBtnClass );
6162 $( this ).addClass( $.mobile.activeBtnClass );
6163
6164 // The code below is a workaround to fix #1181
6165 var activeBtn = $( this );
6166
6167 $( document ).one( "pagehide", function() {
6168 activeBtn.removeClass( $.mobile.activeBtnClass );
6169 });
6170 }
6171 });
6172
6173 // Buttons in the navbar with ui-state-persist class should regain their active state before page show
6174 $navbar.closest( ".ui-page" ).bind( "pagebeforeshow", function() {
6175 $navbtns.filter( ".ui-state-persist" ).addClass( $.mobile.activeBtnClass );
6176 });
6177 }
6178});
6179
6180//auto self-init widgets
6181$.mobile.document.bind( "pagecreate create", function( e ) {
6182 $.mobile.navbar.prototype.enhanceWithin( e.target );
6183});
6184
6185})( jQuery );
6186
6187(function( $, undefined ) {
6188
6189//Keeps track of the number of lists per page UID
6190//This allows support for multiple nested list in the same page
6191//https://github.com/jquery/jquery-mobile/issues/1617
6192var listCountPerPage = {};
6193
6194$.widget( "mobile.listview", $.mobile.widget, $.extend( {
6195
6196 options: {
6197 theme: null,
6198 countTheme: "c",
6199 headerTheme: "b",
6200 dividerTheme: "b",
6201 icon: "arrow-r",
6202 splitIcon: "arrow-r",
6203 splitTheme: "b",
6204 corners: true,
6205 shadow: true,
6206 inset: false,
6207 initSelector: ":jqmData(role='listview')"
6208 },
6209
6210 _create: function() {
6211 var t = this,
6212 listviewClasses = "";
6213
6214 listviewClasses += t.options.inset ? " ui-listview-inset" : "";
6215
6216 if ( !!t.options.inset ) {
6217 listviewClasses += t.options.corners ? " ui-corner-all" : "";
6218 listviewClasses += t.options.shadow ? " ui-shadow" : "";
6219 }
6220
6221 // create listview markup
6222 t.element.addClass(function( i, orig ) {
6223 return orig + " ui-listview" + listviewClasses;
6224 });
6225
6226 t.refresh( true );
6227 },
6228
6229 // This is a generic utility method for finding the first
6230 // node with a given nodeName. It uses basic DOM traversal
6231 // to be fast and is meant to be a substitute for simple
6232 // $.fn.closest() and $.fn.children() calls on a single
6233 // element. Note that callers must pass both the lowerCase
6234 // and upperCase version of the nodeName they are looking for.
6235 // The main reason for this is that this function will be
6236 // called many times and we want to avoid having to lowercase
6237 // the nodeName from the element every time to ensure we have
6238 // a match. Note that this function lives here for now, but may
6239 // be moved into $.mobile if other components need a similar method.
6240 _findFirstElementByTagName: function( ele, nextProp, lcName, ucName ) {
6241 var dict = {};
6242 dict[ lcName ] = dict[ ucName ] = true;
6243 while ( ele ) {
6244 if ( dict[ ele.nodeName ] ) {
6245 return ele;
6246 }
6247 ele = ele[ nextProp ];
6248 }
6249 return null;
6250 },
6251 _getChildrenByTagName: function( ele, lcName, ucName ) {
6252 var results = [],
6253 dict = {};
6254 dict[ lcName ] = dict[ ucName ] = true;
6255 ele = ele.firstChild;
6256 while ( ele ) {
6257 if ( dict[ ele.nodeName ] ) {
6258 results.push( ele );
6259 }
6260 ele = ele.nextSibling;
6261 }
6262 return $( results );
6263 },
6264
6265 _addThumbClasses: function( containers ) {
6266 var i, img, len = containers.length;
6267 for ( i = 0; i < len; i++ ) {
6268 img = $( this._findFirstElementByTagName( containers[ i ].firstChild, "nextSibling", "img", "IMG" ) );
6269 if ( img.length ) {
6270 img.addClass( "ui-li-thumb" );
6271 $( this._findFirstElementByTagName( img[ 0 ].parentNode, "parentNode", "li", "LI" ) ).addClass( img.is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
6272 }
6273 }
6274 },
6275
6276 refresh: function( create ) {
6277 this.parentPage = this.element.closest( ".ui-page" );
6278 this._createSubPages();
6279
6280 var o = this.options,
6281 $list = this.element,
6282 self = this,
6283 dividertheme = $list.jqmData( "dividertheme" ) || o.dividerTheme,
6284 listsplittheme = $list.jqmData( "splittheme" ),
6285 listspliticon = $list.jqmData( "spliticon" ),
6286 listicon = $list.jqmData( "icon" ),
6287 li = this._getChildrenByTagName( $list[ 0 ], "li", "LI" ),
6288 ol = !!$.nodeName( $list[ 0 ], "ol" ),
6289 jsCount = !$.support.cssPseudoElement,
6290 start = $list.attr( "start" ),
6291 itemClassDict = {},
6292 item, itemClass, itemTheme,
6293 a, last, splittheme, counter, startCount, newStartCount, countParent, icon, imgParents, img, linkIcon;
6294
6295 if ( ol && jsCount ) {
6296 $list.find( ".ui-li-dec" ).remove();
6297 }
6298
6299 if ( ol ) {
6300 // Check if a start attribute has been set while taking a value of 0 into account
6301 if ( start || start === 0 ) {
6302 if ( !jsCount ) {
6303 startCount = parseInt( start , 10 ) - 1;
6304 $list.css( "counter-reset", "listnumbering " + startCount );
6305 } else {
6306 counter = parseInt( start , 10 );
6307 }
6308 } else if ( jsCount ) {
6309 counter = 1;
6310 }
6311 }
6312
6313 if ( !o.theme ) {
6314 o.theme = $.mobile.getInheritedTheme( this.element, "c" );
6315 }
6316
6317 for ( var pos = 0, numli = li.length; pos < numli; pos++ ) {
6318 item = li.eq( pos );
6319 itemClass = "ui-li";
6320
6321 // If we're creating the element, we update it regardless
6322 if ( create || !item.hasClass( "ui-li" ) ) {
6323 itemTheme = item.jqmData( "theme" ) || o.theme;
6324 a = this._getChildrenByTagName( item[ 0 ], "a", "A" );
6325 var isDivider = ( item.jqmData( "role" ) === "list-divider" );
6326
6327 if ( a.length && !isDivider ) {
6328 icon = item.jqmData( "icon" );
6329
6330 item.buttonMarkup({
6331 wrapperEls: "div",
6332 shadow: false,
6333 corners: false,
6334 iconpos: "right",
6335 icon: a.length > 1 || icon === false ? false : icon || listicon || o.icon,
6336 theme: itemTheme
6337 });
6338
6339 if ( ( icon !== false ) && ( a.length === 1 ) ) {
6340 item.addClass( "ui-li-has-arrow" );
6341 }
6342
6343 a.first().removeClass( "ui-link" ).addClass( "ui-link-inherit" );
6344
6345 if ( a.length > 1 ) {
6346 itemClass += " ui-li-has-alt";
6347
6348 last = a.last();
6349 splittheme = listsplittheme || last.jqmData( "theme" ) || o.splitTheme;
6350 linkIcon = last.jqmData( "icon" );
6351
6352 last.appendTo( item )
6353 .attr( "title", $.trim(last.getEncodedText()) )
6354 .addClass( "ui-li-link-alt" )
6355 .empty()
6356 .buttonMarkup({
6357 shadow: false,
6358 corners: false,
6359 theme: itemTheme,
6360 icon: false,
6361 iconpos: "notext"
6362 })
6363 .find( ".ui-btn-inner" )
6364 .append(
6365 $( document.createElement( "span" ) ).buttonMarkup({
6366 shadow: true,
6367 corners: true,
6368 theme: splittheme,
6369 iconpos: "notext",
6370 // link icon overrides list item icon overrides ul element overrides options
6371 icon: linkIcon || icon || listspliticon || o.splitIcon
6372 })
6373 );
6374 }
6375 } else if ( isDivider ) {
6376
6377 itemClass += " ui-li-divider ui-bar-" + ( item.jqmData( "theme" ) || dividertheme );
6378 item.attr( "role", "heading" );
6379
6380 if ( ol ) {
6381 //reset counter when a divider heading is encountered
6382 if ( start || start === 0 ) {
6383 if ( !jsCount ) {
6384 newStartCount = parseInt( start , 10 ) - 1;
6385 item.css( "counter-reset", "listnumbering " + newStartCount );
6386 } else {
6387 counter = parseInt( start , 10 );
6388 }
6389 } else if ( jsCount ) {
6390 counter = 1;
6391 }
6392 }
6393
6394 } else {
6395 itemClass += " ui-li-static ui-btn-up-" + itemTheme;
6396 }
6397 }
6398
6399 if ( ol && jsCount && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
6400 countParent = itemClass.indexOf( "ui-li-static" ) > 0 ? item : item.find( ".ui-link-inherit" );
6401
6402 countParent.addClass( "ui-li-jsnumbering" )
6403 .prepend( "<span class='ui-li-dec'>" + ( counter++ ) + ". </span>" );
6404 }
6405
6406 // Instead of setting item class directly on the list item and its
6407 // btn-inner at this point in time, push the item into a dictionary
6408 // that tells us what class to set on it so we can do this after this
6409 // processing loop is finished.
6410
6411 if ( !itemClassDict[ itemClass ] ) {
6412 itemClassDict[ itemClass ] = [];
6413 }
6414
6415 itemClassDict[ itemClass ].push( item[ 0 ] );
6416 }
6417
6418 // Set the appropriate listview item classes on each list item
6419 // and their btn-inner elements. The main reason we didn't do this
6420 // in the for-loop above is because we can eliminate per-item function overhead
6421 // by calling addClass() and children() once or twice afterwards. This
6422 // can give us a significant boost on platforms like WP7.5.
6423
6424 for ( itemClass in itemClassDict ) {
6425 $( itemClassDict[ itemClass ] ).addClass( itemClass ).children( ".ui-btn-inner" ).addClass( itemClass );
6426 }
6427
6428 $list.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" )
6429 .end()
6430
6431 .find( "p, dl" ).addClass( "ui-li-desc" )
6432 .end()
6433
6434 .find( ".ui-li-aside" ).each(function() {
6435 var $this = $( this );
6436 $this.prependTo( $this.parent() ); //shift aside to front for css float
6437 })
6438 .end()
6439
6440 .find( ".ui-li-count" ).each(function() {
6441 $( this ).closest( "li" ).addClass( "ui-li-has-count" );
6442 }).addClass( "ui-btn-up-" + ( $list.jqmData( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );
6443
6444 // The idea here is to look at the first image in the list item
6445 // itself, and any .ui-link-inherit element it may contain, so we
6446 // can place the appropriate classes on the image and list item.
6447 // Note that we used to use something like:
6448 //
6449 // li.find(">img:eq(0), .ui-link-inherit>img:eq(0)").each( ... );
6450 //
6451 // But executing a find() like that on Windows Phone 7.5 took a
6452 // really long time. Walking things manually with the code below
6453 // allows the 400 listview item page to load in about 3 seconds as
6454 // opposed to 30 seconds.
6455
6456 this._addThumbClasses( li );
6457 this._addThumbClasses( $list.find( ".ui-link-inherit" ) );
6458
6459 this._addFirstLastClasses( li, this._getVisibles( li, create ), create );
6460 // autodividers binds to this to redraw dividers after the listview refresh
6461 this._trigger( "afterrefresh" );
6462 },
6463
6464 //create a string for ID/subpage url creation
6465 _idStringEscape: function( str ) {
6466 return str.replace(/[^a-zA-Z0-9]/g, '-');
6467 },
6468
6469 _createSubPages: function() {
6470 var parentList = this.element,
6471 parentPage = parentList.closest( ".ui-page" ),
6472 parentUrl = parentPage.jqmData( "url" ),
6473 parentId = parentUrl || parentPage[ 0 ][ $.expando ],
6474 parentListId = parentList.attr( "id" ),
6475 o = this.options,
6476 dns = "data-" + $.mobile.ns,
6477 self = this,
6478 persistentFooterID = parentPage.find( ":jqmData(role='footer')" ).jqmData( "id" ),
6479 hasSubPages;
6480
6481 if ( typeof listCountPerPage[ parentId ] === "undefined" ) {
6482 listCountPerPage[ parentId ] = -1;
6483 }
6484
6485 parentListId = parentListId || ++listCountPerPage[ parentId ];
6486
6487 $( parentList.find( "li>ul, li>ol" ).toArray().reverse() ).each(function( i ) {
6488 var self = this,
6489 list = $( this ),
6490 listId = list.attr( "id" ) || parentListId + "-" + i,
6491 parent = list.parent(),
6492 nodeElsFull = $( list.prevAll().toArray().reverse() ),
6493 nodeEls = nodeElsFull.length ? nodeElsFull : $( "<span>" + $.trim(parent.contents()[ 0 ].nodeValue) + "</span>" ),
6494 title = nodeEls.first().getEncodedText(),//url limits to first 30 chars of text
6495 id = ( parentUrl || "" ) + "&" + $.mobile.subPageUrlKey + "=" + listId,
6496 theme = list.jqmData( "theme" ) || o.theme,
6497 countTheme = list.jqmData( "counttheme" ) || parentList.jqmData( "counttheme" ) || o.countTheme,
6498 newPage, anchor;
6499
6500 //define hasSubPages for use in later removal
6501 hasSubPages = true;
6502
6503 newPage = list.detach()
6504 .wrap( "<div " + dns + "role='page' " + dns + "url='" + id + "' " + dns + "theme='" + theme + "' " + dns + "count-theme='" + countTheme + "'><div " + dns + "role='content'></div></div>" )
6505 .parent()
6506 .before( "<div " + dns + "role='header' " + dns + "theme='" + o.headerTheme + "'><div class='ui-title'>" + title + "</div></div>" )
6507 .after( persistentFooterID ? $( "<div " + dns + "role='footer' " + dns + "id='"+ persistentFooterID +"'>" ) : "" )
6508 .parent()
6509 .appendTo( $.mobile.pageContainer );
6510
6511 newPage.page();
6512
6513 anchor = parent.find( 'a:first' );
6514
6515 if ( !anchor.length ) {
6516 anchor = $( "<a/>" ).html( nodeEls || title ).prependTo( parent.empty() );
6517 }
6518
6519 anchor.attr( "href", "#" + id );
6520
6521 }).listview();
6522
6523 // on pagehide, remove any nested pages along with the parent page, as long as they aren't active
6524 // and aren't embedded
6525 if ( hasSubPages &&
6526 parentPage.is( ":jqmData(external-page='true')" ) &&
6527 parentPage.data( "mobile-page" ).options.domCache === false ) {
6528
6529 var newRemove = function( e, ui ) {
6530 var nextPage = ui.nextPage, npURL,
6531 prEvent = new $.Event( "pageremove" );
6532
6533 if ( ui.nextPage ) {
6534 npURL = nextPage.jqmData( "url" );
6535 if ( npURL.indexOf( parentUrl + "&" + $.mobile.subPageUrlKey ) !== 0 ) {
6536 self.childPages().remove();
6537 parentPage.trigger( prEvent );
6538 if ( !prEvent.isDefaultPrevented() ) {
6539 parentPage.removeWithDependents();
6540 }
6541 }
6542 }
6543 };
6544
6545 // unbind the original page remove and replace with our specialized version
6546 parentPage
6547 .unbind( "pagehide.remove" )
6548 .bind( "pagehide.remove", newRemove);
6549 }
6550 },
6551
6552 // TODO sort out a better way to track sub pages of the listview this is brittle
6553 childPages: function() {
6554 var parentUrl = this.parentPage.jqmData( "url" );
6555
6556 return $( ":jqmData(url^='"+ parentUrl + "&" + $.mobile.subPageUrlKey + "')" );
6557 }
6558}, $.mobile.behaviors.addFirstLastClasses ) );
6559
6560//auto self-init widgets
6561$.mobile.document.bind( "pagecreate create", function( e ) {
6562 $.mobile.listview.prototype.enhanceWithin( e.target );
6563});
6564
6565})( jQuery );
6566
6567(function( $ ) {
6568 var meta = $( "meta[name=viewport]" ),
6569 initialContent = meta.attr( "content" ),
6570 disabledZoom = initialContent + ",maximum-scale=1, user-scalable=no",
6571 enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes",
6572 disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test( initialContent );
6573
6574 $.mobile.zoom = $.extend( {}, {
6575 enabled: !disabledInitially,
6576 locked: false,
6577 disable: function( lock ) {
6578 if ( !disabledInitially && !$.mobile.zoom.locked ) {
6579 meta.attr( "content", disabledZoom );
6580 $.mobile.zoom.enabled = false;
6581 $.mobile.zoom.locked = lock || false;
6582 }
6583 },
6584 enable: function( unlock ) {
6585 if ( !disabledInitially && ( !$.mobile.zoom.locked || unlock === true ) ) {
6586 meta.attr( "content", enabledZoom );
6587 $.mobile.zoom.enabled = true;
6588 $.mobile.zoom.locked = false;
6589 }
6590 },
6591 restore: function() {
6592 if ( !disabledInitially ) {
6593 meta.attr( "content", initialContent );
6594 $.mobile.zoom.enabled = true;
6595 }
6596 }
6597 });
6598
6599}( jQuery ));
6600
6601(function( $, undefined ) {
6602
6603$.widget( "mobile.textinput", $.mobile.widget, {
6604 options: {
6605 theme: null,
6606 mini: false,
6607 // This option defaults to true on iOS devices.
6608 preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
6609 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]), input[type='file']",
6610 clearBtn: false,
6611 clearSearchButtonText: null, //deprecating for 1.3...
6612 clearBtnText: "clear text",
6613 disabled: false
6614 },
6615
6616 _create: function() {
6617
6618 var self = this,
6619 input = this.element,
6620 o = this.options,
6621 theme = o.theme || $.mobile.getInheritedTheme( this.element, "c" ),
6622 themeclass = " ui-body-" + theme,
6623 miniclass = o.mini ? " ui-mini" : "",
6624 isSearch = input.is( "[type='search'], :jqmData(type='search')" ),
6625 focusedEl,
6626 clearbtn,
6627 clearBtnText = o.clearSearchButtonText || o.clearBtnText,
6628 clearBtnBlacklist = input.is( "textarea, :jqmData(type='range')" ),
6629 inputNeedsClearBtn = !!o.clearBtn && !clearBtnBlacklist,
6630 inputNeedsWrap = input.is( "input" ) && !input.is( ":jqmData(type='range')" );
6631
6632 function toggleClear() {
6633 setTimeout( function() {
6634 clearbtn.toggleClass( "ui-input-clear-hidden", !input.val() );
6635 }, 0 );
6636 }
6637
6638 $( "label[for='" + input.attr( "id" ) + "']" ).addClass( "ui-input-text" );
6639
6640 focusedEl = input.addClass( "ui-input-text ui-body-"+ theme );
6641
6642 // XXX: Temporary workaround for issue 785 (Apple bug 8910589).
6643 // Turn off autocorrect and autocomplete on non-iOS 5 devices
6644 // since the popup they use can't be dismissed by the user. Note
6645 // that we test for the presence of the feature by looking for
6646 // the autocorrect property on the input element. We currently
6647 // have no test for iOS 5 or newer so we're temporarily using
6648 // the touchOverflow support flag for jQM 1.0. Yes, I feel dirty. - jblas
6649 if ( typeof input[0].autocorrect !== "undefined" && !$.support.touchOverflow ) {
6650 // Set the attribute instead of the property just in case there
6651 // is code that attempts to make modifications via HTML.
6652 input[0].setAttribute( "autocorrect", "off" );
6653 input[0].setAttribute( "autocomplete", "off" );
6654 }
6655
6656 //"search" and "text" input widgets
6657 if ( isSearch ) {
6658 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();
6659 } else if ( inputNeedsWrap ) {
6660 focusedEl = input.wrap( "<div class='ui-input-text ui-shadow-inset ui-corner-all ui-btn-shadow" + themeclass + miniclass + "'></div>" ).parent();
6661 }
6662
6663 if( inputNeedsClearBtn || isSearch ) {
6664 clearbtn = $( "<a href='#' class='ui-input-clear' title='" + clearBtnText + "'>" + clearBtnText + "</a>" )
6665 .bind( "click", function( event ) {
6666 input
6667 .val( "" )
6668 .focus()
6669 .trigger( "change" );
6670 clearbtn.addClass( "ui-input-clear-hidden" );
6671 event.preventDefault();
6672 })
6673 .appendTo( focusedEl )
6674 .buttonMarkup({
6675 icon: "delete",
6676 iconpos: "notext",
6677 corners: true,
6678 shadow: true,
6679 mini: o.mini
6680 });
6681
6682 if ( !isSearch ) {
6683 focusedEl.addClass( "ui-input-has-clear" );
6684 }
6685
6686 toggleClear();
6687
6688 input.bind( "paste cut keyup input focus change blur", toggleClear );
6689 }
6690 else if ( !inputNeedsWrap && !isSearch ) {
6691 input.addClass( "ui-corner-all ui-shadow-inset" + themeclass + miniclass );
6692 }
6693
6694 input.focus(function() {
6695 // In many situations, iOS will zoom into the input upon tap, this prevents that from happening
6696 if ( o.preventFocusZoom ) {
6697 $.mobile.zoom.disable( true );
6698 }
6699 focusedEl.addClass( $.mobile.focusClass );
6700 })
6701 .blur(function() {
6702 focusedEl.removeClass( $.mobile.focusClass );
6703 if ( o.preventFocusZoom ) {
6704 $.mobile.zoom.enable( true );
6705 }
6706 });
6707
6708 // Autogrow
6709 if ( input.is( "textarea" ) ) {
6710 var extraLineHeight = 15,
6711 keyupTimeoutBuffer = 100,
6712 keyupTimeout;
6713
6714 this._keyup = function() {
6715 var scrollHeight = input[ 0 ].scrollHeight,
6716 clientHeight = input[ 0 ].clientHeight;
6717
6718 if ( clientHeight < scrollHeight ) {
6719 var paddingTop = parseFloat( input.css( "padding-top" ) ),
6720 paddingBottom = parseFloat( input.css( "padding-bottom" ) ),
6721 paddingHeight = paddingTop + paddingBottom;
6722
6723 input.height( scrollHeight - paddingHeight + extraLineHeight );
6724 }
6725 };
6726
6727 input.on( "keyup change input paste", function() {
6728 clearTimeout( keyupTimeout );
6729 keyupTimeout = setTimeout( self._keyup, keyupTimeoutBuffer );
6730 });
6731
6732 // binding to pagechange here ensures that for pages loaded via
6733 // ajax the height is recalculated without user input
6734 this._on( true, $.mobile.document, { "pagechange": "_keyup" });
6735
6736 // Issue 509: the browser is not providing scrollHeight properly until the styles load
6737 if ( $.trim( input.val() ) ) {
6738 // bind to the window load to make sure the height is calculated based on BOTH
6739 // the DOM and CSS
6740 this._on( true, $.mobile.window, {"load": "_keyup"});
6741 }
6742 }
6743 if ( input.attr( "disabled" ) ) {
6744 this.disable();
6745 }
6746 },
6747
6748 disable: function() {
6749 var $el,
6750 isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
6751 inputNeedsWrap = this.element.is( "input" ) && !this.element.is( ":jqmData(type='range')" ),
6752 parentNeedsDisabled = this.element.attr( "disabled", true ) && ( inputNeedsWrap || isSearch );
6753
6754 if ( parentNeedsDisabled ) {
6755 $el = this.element.parent();
6756 } else {
6757 $el = this.element;
6758 }
6759 $el.addClass( "ui-disabled" );
6760 return this._setOption( "disabled", true );
6761 },
6762
6763 enable: function() {
6764 var $el,
6765 isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
6766 inputNeedsWrap = this.element.is( "input" ) && !this.element.is( ":jqmData(type='range')" ),
6767 parentNeedsEnabled = this.element.attr( "disabled", false ) && ( inputNeedsWrap || isSearch );
6768
6769 if ( parentNeedsEnabled ) {
6770 $el = this.element.parent();
6771 } else {
6772 $el = this.element;
6773 }
6774 $el.removeClass( "ui-disabled" );
6775 return this._setOption( "disabled", false );
6776 }
6777});
6778
6779//auto self-init widgets
6780$.mobile.document.bind( "pagecreate create", function( e ) {
6781 $.mobile.textinput.prototype.enhanceWithin( e.target, true );
6782});
6783
6784})( jQuery );
6785
6786(function( $, undefined ) {
6787
6788$.mobile.listview.prototype.options.filter = false;
6789$.mobile.listview.prototype.options.filterPlaceholder = "Filter items...";
6790$.mobile.listview.prototype.options.filterTheme = "c";
6791$.mobile.listview.prototype.options.filterReveal = false;
6792// TODO rename callback/deprecate and default to the item itself as the first argument
6793var defaultFilterCallback = function( text, searchValue, item ) {
6794 return text.toString().toLowerCase().indexOf( searchValue ) === -1;
6795 };
6796
6797$.mobile.listview.prototype.options.filterCallback = defaultFilterCallback;
6798
6799$.mobile.document.delegate( "ul, ol", "listviewcreate", function() {
6800 var list = $( this ),
6801 listview = list.data( "mobile-listview" );
6802
6803 if ( !listview || !listview.options.filter ) {
6804 return;
6805 }
6806
6807 if ( listview.options.filterReveal ) {
6808 list.children().addClass( "ui-screen-hidden" );
6809 }
6810
6811 var wrapper = $( "<form>", {
6812 "class": "ui-listview-filter ui-bar-" + listview.options.filterTheme,
6813 "role": "search"
6814 }).submit( function( e ) {
6815 e.preventDefault();
6816 search.blur();
6817 }),
6818 onKeyUp = function( e ) {
6819 var $this = $( this ),
6820 val = this.value.toLowerCase(),
6821 listItems = null,
6822 li = list.children(),
6823 lastval = $this.jqmData( "lastval" ) + "",
6824 childItems = false,
6825 itemtext = "",
6826 item,
6827 // Check if a custom filter callback applies
6828 isCustomFilterCallback = listview.options.filterCallback !== defaultFilterCallback;
6829
6830 if ( lastval && lastval === val ) {
6831 // Execute the handler only once per value change
6832 return;
6833 }
6834
6835 listview._trigger( "beforefilter", "beforefilter", { input: this } );
6836
6837 // Change val as lastval for next execution
6838 $this.jqmData( "lastval" , val );
6839 if ( isCustomFilterCallback || val.length < lastval.length || val.indexOf( lastval ) !== 0 ) {
6840
6841 // Custom filter callback applies or removed chars or pasted something totally different, check all items
6842 listItems = list.children();
6843 } else {
6844
6845 // Only chars added, not removed, only use visible subset
6846 listItems = list.children( ":not(.ui-screen-hidden)" );
6847
6848 if ( !listItems.length && listview.options.filterReveal ) {
6849 listItems = list.children( ".ui-screen-hidden" );
6850 }
6851 }
6852
6853 if ( val ) {
6854
6855 // This handles hiding regular rows without the text we search for
6856 // and any list dividers without regular rows shown under it
6857
6858 for ( var i = listItems.length - 1; i >= 0; i-- ) {
6859 item = $( listItems[ i ] );
6860 itemtext = item.jqmData( "filtertext" ) || item.text();
6861
6862 if ( item.is( "li:jqmData(role=list-divider)" ) ) {
6863
6864 item.toggleClass( "ui-filter-hidequeue" , !childItems );
6865
6866 // New bucket!
6867 childItems = false;
6868
6869 } else if ( listview.options.filterCallback( itemtext, val, item ) ) {
6870
6871 //mark to be hidden
6872 item.toggleClass( "ui-filter-hidequeue" , true );
6873 } else {
6874
6875 // There's a shown item in the bucket
6876 childItems = true;
6877 }
6878 }
6879
6880 // Show items, not marked to be hidden
6881 listItems
6882 .filter( ":not(.ui-filter-hidequeue)" )
6883 .toggleClass( "ui-screen-hidden", false );
6884
6885 // Hide items, marked to be hidden
6886 listItems
6887 .filter( ".ui-filter-hidequeue" )
6888 .toggleClass( "ui-screen-hidden", true )
6889 .toggleClass( "ui-filter-hidequeue", false );
6890
6891 } else {
6892
6893 //filtervalue is empty => show all
6894 listItems.toggleClass( "ui-screen-hidden", !!listview.options.filterReveal );
6895 }
6896 listview._addFirstLastClasses( li, listview._getVisibles( li, false ), false );
6897 },
6898 search = $( "<input>", {
6899 placeholder: listview.options.filterPlaceholder
6900 })
6901 .attr( "data-" + $.mobile.ns + "type", "search" )
6902 .jqmData( "lastval", "" )
6903 .bind( "keyup change input", onKeyUp )
6904 .appendTo( wrapper )
6905 .textinput();
6906
6907 if ( listview.options.inset ) {
6908 wrapper.addClass( "ui-listview-filter-inset" );
6909 }
6910
6911 wrapper.bind( "submit", function() {
6912 return false;
6913 })
6914 .insertBefore( list );
6915});
6916
6917})( jQuery );
6918
6919(function( $, undefined ) {
6920
6921$.mobile.listview.prototype.options.autodividers = false;
6922$.mobile.listview.prototype.options.autodividersSelector = function( elt ) {
6923 // look for the text in the given element
6924 var text = $.trim( elt.text() ) || null;
6925
6926 if ( !text ) {
6927 return null;
6928 }
6929
6930 // create the text for the divider (first uppercased letter)
6931 text = text.slice( 0, 1 ).toUpperCase();
6932
6933 return text;
6934};
6935
6936$.mobile.document.delegate( "ul,ol", "listviewcreate", function() {
6937
6938 var list = $( this ),
6939 listview = list.data( "mobile-listview" );
6940
6941 if ( !listview || !listview.options.autodividers ) {
6942 return;
6943 }
6944
6945 var replaceDividers = function () {
6946 list.find( "li:jqmData(role='list-divider')" ).remove();
6947
6948 var lis = list.find( 'li' ),
6949 lastDividerText = null, li, dividerText;
6950
6951 for ( var i = 0; i < lis.length ; i++ ) {
6952 li = lis[i];
6953 dividerText = listview.options.autodividersSelector( $( li ) );
6954
6955 if ( dividerText && lastDividerText !== dividerText ) {
6956 var divider = document.createElement( 'li' );
6957 divider.appendChild( document.createTextNode( dividerText ) );
6958 divider.setAttribute( 'data-' + $.mobile.ns + 'role', 'list-divider' );
6959 li.parentNode.insertBefore( divider, li );
6960 }
6961
6962 lastDividerText = dividerText;
6963 }
6964 };
6965
6966 var afterListviewRefresh = function () {
6967 list.unbind( 'listviewafterrefresh', afterListviewRefresh );
6968 replaceDividers();
6969 listview.refresh();
6970 list.bind( 'listviewafterrefresh', afterListviewRefresh );
6971 };
6972
6973 afterListviewRefresh();
6974});
6975
6976})( jQuery );
6977
6978(function( $, undefined ) {
6979
6980$( document ).bind( "pagecreate create", function( e ) {
6981 $( ":jqmData(role='nojs')", e.target ).addClass( "ui-nojs" );
6982
6983});
6984
6985})( jQuery );
6986
6987(function( $, undefined ) {
6988
6989$.mobile.behaviors.formReset = {
6990 _handleFormReset: function() {
6991 this._on( this.element.closest( "form" ), {
6992 reset: function() {
6993 this._delay( "_reset" );
6994 }
6995 });
6996 }
6997};
6998
6999})( jQuery );
7000
7001/*
7002* "checkboxradio" plugin
7003*/
7004
7005(function( $, undefined ) {
7006
7007$.widget( "mobile.checkboxradio", $.mobile.widget, $.extend( {
7008 options: {
7009 theme: null,
7010 mini: false,
7011 initSelector: "input[type='checkbox'],input[type='radio']"
7012 },
7013 _create: function() {
7014 var self = this,
7015 input = this.element,
7016 o = this.options,
7017 inheritAttr = function( input, dataAttr ) {
7018 return input.jqmData( dataAttr ) || input.closest( "form, fieldset" ).jqmData( dataAttr );
7019 },
7020 // NOTE: Windows Phone could not find the label through a selector
7021 // filter works though.
7022 parentLabel = $( input ).closest( "label" ),
7023 label = parentLabel.length ? parentLabel : $( input ).closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" ).find( "label" ).filter( "[for='" + input[0].id + "']" ).first(),
7024 inputtype = input[0].type,
7025 mini = inheritAttr( input, "mini" ) || o.mini,
7026 checkedState = inputtype + "-on",
7027 uncheckedState = inputtype + "-off",
7028 iconpos = inheritAttr( input, "iconpos" ),
7029 checkedClass = "ui-" + checkedState,
7030 uncheckedClass = "ui-" + uncheckedState;
7031
7032 if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
7033 return;
7034 }
7035
7036 // Expose for other methods
7037 $.extend( this, {
7038 label: label,
7039 inputtype: inputtype,
7040 checkedClass: checkedClass,
7041 uncheckedClass: uncheckedClass,
7042 checkedicon: checkedState,
7043 uncheckedicon: uncheckedState
7044 });
7045
7046 // If there's no selected theme check the data attr
7047 if ( !o.theme ) {
7048 o.theme = $.mobile.getInheritedTheme( this.element, "c" );
7049 }
7050
7051 label.buttonMarkup({
7052 theme: o.theme,
7053 icon: uncheckedState,
7054 shadow: false,
7055 mini: mini,
7056 iconpos: iconpos
7057 });
7058
7059 // Wrap the input + label in a div
7060 var wrapper = document.createElement('div');
7061 wrapper.className = 'ui-' + inputtype;
7062
7063 input.add( label ).wrapAll( wrapper );
7064
7065 label.bind({
7066 vmouseover: function( event ) {
7067 if ( $( this ).parent().is( ".ui-disabled" ) ) {
7068 event.stopPropagation();
7069 }
7070 },
7071
7072 vclick: function( event ) {
7073 if ( input.is( ":disabled" ) ) {
7074 event.preventDefault();
7075 return;
7076 }
7077
7078 self._cacheVals();
7079
7080 input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
7081
7082 // trigger click handler's bound directly to the input as a substitute for
7083 // how label clicks behave normally in the browsers
7084 // TODO: it would be nice to let the browser's handle the clicks and pass them
7085 // through to the associate input. we can swallow that click at the parent
7086 // wrapper element level
7087 input.triggerHandler( 'click' );
7088
7089 // Input set for common radio buttons will contain all the radio
7090 // buttons, but will not for checkboxes. clearing the checked status
7091 // of other radios ensures the active button state is applied properly
7092 self._getInputSet().not( input ).prop( "checked", false );
7093
7094 self._updateAll();
7095 return false;
7096 }
7097 });
7098
7099 input
7100 .bind({
7101 vmousedown: function() {
7102 self._cacheVals();
7103 },
7104
7105 vclick: function() {
7106 var $this = $( this );
7107
7108 // Adds checked attribute to checked input when keyboard is used
7109 if ( $this.is( ":checked" ) ) {
7110
7111 $this.prop( "checked", true);
7112 self._getInputSet().not( $this ).prop( "checked", false );
7113 } else {
7114
7115 $this.prop( "checked", false );
7116 }
7117
7118 self._updateAll();
7119 },
7120
7121 focus: function() {
7122 label.addClass( $.mobile.focusClass );
7123 },
7124
7125 blur: function() {
7126 label.removeClass( $.mobile.focusClass );
7127 }
7128 });
7129
7130 this._handleFormReset();
7131 this.refresh();
7132 },
7133
7134 _cacheVals: function() {
7135 this._getInputSet().each(function() {
7136 $( this ).jqmData( "cacheVal", this.checked );
7137 });
7138 },
7139
7140 //returns either a set of radios with the same name attribute, or a single checkbox
7141 _getInputSet: function() {
7142 if ( this.inputtype === "checkbox" ) {
7143 return this.element;
7144 }
7145
7146 return this.element.closest( "form, :jqmData(role='page'), :jqmData(role='dialog')" )
7147 .find( "input[name='" + this.element[0].name + "'][type='" + this.inputtype + "']" );
7148 },
7149
7150 _updateAll: function() {
7151 var self = this;
7152
7153 this._getInputSet().each(function() {
7154 var $this = $( this );
7155
7156 if ( this.checked || self.inputtype === "checkbox" ) {
7157 $this.trigger( "change" );
7158 }
7159 })
7160 .checkboxradio( "refresh" );
7161 },
7162
7163 _reset: function() {
7164 this.refresh();
7165 },
7166
7167 refresh: function() {
7168 var input = this.element[ 0 ],
7169 active = " " + $.mobile.activeBtnClass,
7170 checkedClass = this.checkedClass + ( this.element.parents( ".ui-controlgroup-horizontal" ).length ? active : "" ),
7171 label = this.label;
7172
7173 if ( input.checked ) {
7174 label.removeClass( this.uncheckedClass + active ).addClass( checkedClass ).buttonMarkup( { icon: this.checkedicon } );
7175 } else {
7176 label.removeClass( checkedClass ).addClass( this.uncheckedClass ).buttonMarkup( { icon: this.uncheckedicon } );
7177 }
7178
7179 if ( input.disabled ) {
7180 this.disable();
7181 } else {
7182 this.enable();
7183 }
7184 },
7185
7186 disable: function() {
7187 this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
7188 },
7189
7190 enable: function() {
7191 this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
7192 }
7193}, $.mobile.behaviors.formReset ) );
7194
7195//auto self-init widgets
7196$.mobile.document.bind( "pagecreate create", function( e ) {
7197 $.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );
7198});
7199
7200})( jQuery );
7201
7202(function( $, undefined ) {
7203
7204$.widget( "mobile.button", $.mobile.widget, {
7205 options: {
7206 theme: null,
7207 icon: null,
7208 iconpos: null,
7209 corners: true,
7210 shadow: true,
7211 iconshadow: true,
7212 inline: null,
7213 mini: null,
7214 initSelector: "button, [type='button'], [type='submit'], [type='reset']"
7215 },
7216 _create: function() {
7217 var $el = this.element,
7218 $button,
7219 // create a copy of this.options we can pass to buttonMarkup
7220 o = ( function( tdo ) {
7221 var key, ret = {};
7222
7223 for ( key in tdo ) {
7224 if ( tdo[ key ] !== null && key !== "initSelector" ) {
7225 ret[ key ] = tdo[ key ];
7226 }
7227 }
7228
7229 return ret;
7230 } )( this.options ),
7231 classes = "",
7232 $buttonPlaceholder;
7233
7234 // if this is a link, check if it's been enhanced and, if not, use the right function
7235 if ( $el[ 0 ].tagName === "A" ) {
7236 if ( !$el.hasClass( "ui-btn" ) ) {
7237 $el.buttonMarkup();
7238 }
7239 return;
7240 }
7241
7242 // get the inherited theme
7243 // TODO centralize for all widgets
7244 if ( !this.options.theme ) {
7245 this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
7246 }
7247
7248 // 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
7249 /* if ( $el[0].className.length ) {
7250 classes = $el[0].className;
7251 } */
7252 if ( !!~$el[0].className.indexOf( "ui-btn-left" ) ) {
7253 classes = "ui-btn-left";
7254 }
7255
7256 if ( !!~$el[0].className.indexOf( "ui-btn-right" ) ) {
7257 classes = "ui-btn-right";
7258 }
7259
7260 if ( $el.attr( "type" ) === "submit" || $el.attr( "type" ) === "reset" ) {
7261 if ( classes ) {
7262 classes += " ui-submit";
7263 } else {
7264 classes = "ui-submit";
7265 }
7266 }
7267 $( "label[for='" + $el.attr( "id" ) + "']" ).addClass( "ui-submit" );
7268
7269 // Add ARIA role
7270 this.button = $( "<div></div>" )
7271 [ $el.html() ? "html" : "text" ]( $el.html() || $el.val() )
7272 .insertBefore( $el )
7273 .buttonMarkup( o )
7274 .addClass( classes )
7275 .append( $el.addClass( "ui-btn-hidden" ) );
7276
7277 $button = this.button;
7278
7279 $el.bind({
7280 focus: function() {
7281 $button.addClass( $.mobile.focusClass );
7282 },
7283
7284 blur: function() {
7285 $button.removeClass( $.mobile.focusClass );
7286 }
7287 });
7288
7289 this.refresh();
7290 },
7291
7292 _setOption: function( key, value ) {
7293 var op = {};
7294
7295 op[ key ] = value;
7296 if ( key !== "initSelector" ) {
7297 this.button.buttonMarkup( op );
7298 // Record the option change in the options and in the DOM data-* attributes
7299 this.element.attr( "data-" + ( $.mobile.ns || "" ) + ( key.replace( /([A-Z])/, "-$1" ).toLowerCase() ), value );
7300 }
7301 this._super( "_setOption", key, value );
7302 },
7303
7304 enable: function() {
7305 this.element.attr( "disabled", false );
7306 this.button.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
7307 return this._setOption( "disabled", false );
7308 },
7309
7310 disable: function() {
7311 this.element.attr( "disabled", true );
7312 this.button.addClass( "ui-disabled" ).attr( "aria-disabled", true );
7313 return this._setOption( "disabled", true );
7314 },
7315
7316 refresh: function() {
7317 var $el = this.element;
7318
7319 if ( $el.prop("disabled") ) {
7320 this.disable();
7321 } else {
7322 this.enable();
7323 }
7324
7325 // Grab the button's text element from its implementation-independent data item
7326 $( this.button.data( 'buttonElements' ).text )[ $el.html() ? "html" : "text" ]( $el.html() || $el.val() );
7327 }
7328});
7329
7330//auto self-init widgets
7331$.mobile.document.bind( "pagecreate create", function( e ) {
7332 $.mobile.button.prototype.enhanceWithin( e.target, true );
7333});
7334
7335})( jQuery );
7336
7337(function( $, undefined ) {
7338
7339$.widget( "mobile.slider", $.mobile.widget, $.extend( {
7340 widgetEventPrefix: "slide",
7341
7342 options: {
7343 theme: null,
7344 trackTheme: null,
7345 disabled: false,
7346 initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",
7347 mini: false,
7348 highlight: false
7349 },
7350
7351 _create: function() {
7352
7353 // TODO: Each of these should have comments explain what they're for
7354 var self = this,
7355 control = this.element,
7356 parentTheme = $.mobile.getInheritedTheme( control, "c" ),
7357 theme = this.options.theme || parentTheme,
7358 trackTheme = this.options.trackTheme || parentTheme,
7359 cType = control[ 0 ].nodeName.toLowerCase(),
7360 isSelect = this.isToggleSwitch = cType === "select",
7361 isRangeslider = control.parent().is( ":jqmData(role='rangeslider')" ),
7362 selectClass = ( this.isToggleSwitch ) ? "ui-slider-switch" : "",
7363 controlID = control.attr( "id" ),
7364 $label = $( "[for='" + controlID + "']" ),
7365 labelID = $label.attr( "id" ) || controlID + "-label",
7366 label = $label.attr( "id", labelID ),
7367 min = !this.isToggleSwitch ? parseFloat( control.attr( "min" ) ) : 0,
7368 max = !this.isToggleSwitch ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
7369 step = window.parseFloat( control.attr( "step" ) || 1 ),
7370 miniClass = ( this.options.mini || control.jqmData( "mini" ) ) ? " ui-mini" : "",
7371 domHandle = document.createElement( "a" ),
7372 handle = $( domHandle ),
7373 domSlider = document.createElement( "div" ),
7374 slider = $( domSlider ),
7375 valuebg = this.options.highlight && !this.isToggleSwitch ? (function() {
7376 var bg = document.createElement( "div" );
7377 bg.className = "ui-slider-bg " + $.mobile.activeBtnClass + " ui-btn-corner-all";
7378 return $( bg ).prependTo( slider );
7379 })() : false,
7380 options,
7381 wrapper;
7382
7383 domHandle.setAttribute( "href", "#" );
7384 domSlider.setAttribute( "role", "application" );
7385 domSlider.className = [this.isToggleSwitch ? "ui-slider " : "ui-slider-track ",selectClass," ui-btn-down-",trackTheme," ui-btn-corner-all", miniClass].join( "" );
7386 domHandle.className = "ui-slider-handle";
7387 domSlider.appendChild( domHandle );
7388
7389 handle.buttonMarkup({ corners: true, theme: theme, shadow: true })
7390 .attr({
7391 "role": "slider",
7392 "aria-valuemin": min,
7393 "aria-valuemax": max,
7394 "aria-valuenow": this._value(),
7395 "aria-valuetext": this._value(),
7396 "title": this._value(),
7397 "aria-labelledby": labelID
7398 });
7399
7400 $.extend( this, {
7401 slider: slider,
7402 handle: handle,
7403 type: cType,
7404 step: step,
7405 max: max,
7406 min: min,
7407 valuebg: valuebg,
7408 isRangeslider: isRangeslider,
7409 dragging: false,
7410 beforeStart: null,
7411 userModified: false,
7412 mouseMoved: false
7413 });
7414
7415 if ( this.isToggleSwitch ) {
7416 wrapper = document.createElement( "div" );
7417 wrapper.className = "ui-slider-inneroffset";
7418
7419 for ( var j = 0, length = domSlider.childNodes.length; j < length; j++ ) {
7420 wrapper.appendChild( domSlider.childNodes[j] );
7421 }
7422
7423 domSlider.appendChild( wrapper );
7424
7425 // slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
7426
7427 // make the handle move with a smooth transition
7428 handle.addClass( "ui-slider-handle-snapping" );
7429
7430 options = control.find( "option" );
7431
7432 for ( var i = 0, optionsCount = options.length; i < optionsCount; i++ ) {
7433 var side = !i ? "b" : "a",
7434 sliderTheme = !i ? " ui-btn-down-" + trackTheme : ( " " + $.mobile.activeBtnClass ),
7435 sliderLabel = document.createElement( "div" ),
7436 sliderImg = document.createElement( "span" );
7437
7438 sliderImg.className = ["ui-slider-label ui-slider-label-", side, sliderTheme, " ui-btn-corner-all"].join( "" );
7439 sliderImg.setAttribute( "role", "img" );
7440 sliderImg.appendChild( document.createTextNode( options[i].innerHTML ) );
7441 $( sliderImg ).prependTo( slider );
7442 }
7443
7444 self._labels = $( ".ui-slider-label", slider );
7445
7446 }
7447
7448 label.addClass( "ui-slider" );
7449
7450 // monitor the input for updated values
7451 control.addClass( this.isToggleSwitch ? "ui-slider-switch" : "ui-slider-input" );
7452
7453 this._on( control, {
7454 "change": "_controlChange",
7455 "keyup": "_controlKeyup",
7456 "blur": "_controlBlur",
7457 "vmouseup": "_controlVMouseUp"
7458 });
7459
7460 slider.bind( "vmousedown", $.proxy( this._sliderVMouseDown, this ) )
7461 .bind( "vclick", false );
7462
7463 // We have to instantiate a new function object for the unbind to work properly
7464 // since the method itself is defined in the prototype (causing it to unbind everything)
7465 this._on( document, { "vmousemove": "_preventDocumentDrag" });
7466 this._on( slider.add( document ), { "vmouseup": "_sliderVMouseUp" });
7467
7468 slider.insertAfter( control );
7469
7470 // wrap in a div for styling purposes
7471 if ( !this.isToggleSwitch && !isRangeslider ) {
7472 wrapper = this.options.mini ? "<div class='ui-slider ui-mini'>" : "<div class='ui-slider'>";
7473
7474 control.add( slider ).wrapAll( wrapper );
7475 }
7476
7477 // Only add focus class to toggle switch, sliders get it automatically from ui-btn
7478 if ( this.isToggleSwitch ) {
7479 this.handle.bind({
7480 focus: function() {
7481 slider.addClass( $.mobile.focusClass );
7482 },
7483
7484 blur: function() {
7485 slider.removeClass( $.mobile.focusClass );
7486 }
7487 });
7488 }
7489
7490 // bind the handle event callbacks and set the context to the widget instance
7491 this._on( this.handle, {
7492 "vmousedown": "_handleVMouseDown",
7493 "keydown": "_handleKeydown",
7494 "keyup": "_handleKeyup"
7495 });
7496
7497 this.handle.bind( "vclick", false );
7498
7499 this._handleFormReset();
7500
7501 this.refresh( undefined, undefined, true );
7502 },
7503
7504 _controlChange: function( event ) {
7505 // if the user dragged the handle, the "change" event was triggered from inside refresh(); don't call refresh() again
7506 if ( this._trigger( "controlchange", event ) === false ) {
7507 return false;
7508 }
7509 if ( !this.mouseMoved ) {
7510 this.refresh( this._value(), true );
7511 }
7512 },
7513
7514 _controlKeyup: function( event ) { // necessary?
7515 this.refresh( this._value(), true, true );
7516 },
7517
7518 _controlBlur: function( event ) {
7519 this.refresh( this._value(), true );
7520 },
7521
7522 // it appears the clicking the up and down buttons in chrome on
7523 // range/number inputs doesn't trigger a change until the field is
7524 // blurred. Here we check thif the value has changed and refresh
7525 _controlVMouseUp: function( event ) {
7526 this._checkedRefresh();
7527 },
7528
7529 // NOTE force focus on handle
7530 _handleVMouseDown: function( event ) {
7531 this.handle.focus();
7532 },
7533
7534 _handleKeydown: function( event ) {
7535 var index = this._value();
7536 if ( this.options.disabled ) {
7537 return;
7538 }
7539
7540 // In all cases prevent the default and mark the handle as active
7541 switch ( event.keyCode ) {
7542 case $.mobile.keyCode.HOME:
7543 case $.mobile.keyCode.END:
7544 case $.mobile.keyCode.PAGE_UP:
7545 case $.mobile.keyCode.PAGE_DOWN:
7546 case $.mobile.keyCode.UP:
7547 case $.mobile.keyCode.RIGHT:
7548 case $.mobile.keyCode.DOWN:
7549 case $.mobile.keyCode.LEFT:
7550 event.preventDefault();
7551
7552 if ( !this._keySliding ) {
7553 this._keySliding = true;
7554 this.handle.addClass( "ui-state-active" );
7555 }
7556
7557 break;
7558 }
7559
7560 // move the slider according to the keypress
7561 switch ( event.keyCode ) {
7562 case $.mobile.keyCode.HOME:
7563 this.refresh( this.min );
7564 break;
7565 case $.mobile.keyCode.END:
7566 this.refresh( this.max );
7567 break;
7568 case $.mobile.keyCode.PAGE_UP:
7569 case $.mobile.keyCode.UP:
7570 case $.mobile.keyCode.RIGHT:
7571 this.refresh( index + this.step );
7572 break;
7573 case $.mobile.keyCode.PAGE_DOWN:
7574 case $.mobile.keyCode.DOWN:
7575 case $.mobile.keyCode.LEFT:
7576 this.refresh( index - this.step );
7577 break;
7578 }
7579 }, // remove active mark
7580
7581 _handleKeyup: function( event ) {
7582 if ( this._keySliding ) {
7583 this._keySliding = false;
7584 this.handle.removeClass( "ui-state-active" );
7585 }
7586 },
7587
7588 _sliderVMouseDown: function( event ) {
7589 // NOTE: we don't do this in refresh because we still want to
7590 // support programmatic alteration of disabled inputs
7591 if ( this.options.disabled || !( event.which === 1 || event.which === 0 || event.which === undefined ) ) {
7592 return false;
7593 }
7594 if ( this._trigger( "beforestart", event ) === false ) {
7595 return false;
7596 }
7597 this.dragging = true;
7598 this.userModified = false;
7599 this.mouseMoved = false;
7600
7601 if ( this.isToggleSwitch ) {
7602 this.beforeStart = this.element[0].selectedIndex;
7603 }
7604
7605
7606 this.refresh( event );
7607 this._trigger( "start" );
7608 return false;
7609 },
7610
7611 _sliderVMouseUp: function() {
7612 if ( this.dragging ) {
7613 this.dragging = false;
7614
7615 if ( this.isToggleSwitch ) {
7616 // make the handle move with a smooth transition
7617 this.handle.addClass( "ui-slider-handle-snapping" );
7618
7619 if ( this.mouseMoved ) {
7620 // this is a drag, change the value only if user dragged enough
7621 if ( this.userModified ) {
7622 this.refresh( this.beforeStart === 0 ? 1 : 0 );
7623 } else {
7624 this.refresh( this.beforeStart );
7625 }
7626 } else {
7627 // this is just a click, change the value
7628 this.refresh( this.beforeStart === 0 ? 1 : 0 );
7629 }
7630 }
7631
7632 this.mouseMoved = false;
7633 this._trigger( "stop" );
7634 return false;
7635 }
7636 },
7637
7638 _preventDocumentDrag: function( event ) {
7639 // NOTE: we don't do this in refresh because we still want to
7640 // support programmatic alteration of disabled inputs
7641 if ( this._trigger( "drag", event ) === false) {
7642 return false;
7643 }
7644 if ( this.dragging && !this.options.disabled ) {
7645
7646 // this.mouseMoved must be updated before refresh() because it will be used in the control "change" event
7647 this.mouseMoved = true;
7648
7649 if ( this.isToggleSwitch ) {
7650 // make the handle move in sync with the mouse
7651 this.handle.removeClass( "ui-slider-handle-snapping" );
7652 }
7653
7654 this.refresh( event );
7655
7656 // only after refresh() you can calculate this.userModified
7657 this.userModified = this.beforeStart !== this.element[0].selectedIndex;
7658 return false;
7659 }
7660 },
7661
7662 _checkedRefresh: function() {
7663 if ( this.value !== this._value() ) {
7664 this.refresh( this._value() );
7665 }
7666 },
7667
7668 _value: function() {
7669 return this.isToggleSwitch ? this.element[0].selectedIndex : parseFloat( this.element.val() ) ;
7670 },
7671
7672
7673 _reset: function() {
7674 this.refresh( undefined, false, true );
7675 },
7676
7677 refresh: function( val, isfromControl, preventInputUpdate ) {
7678 // NOTE: we don't return here because we want to support programmatic
7679 // alteration of the input value, which should still update the slider
7680
7681 var self = this,
7682 parentTheme = $.mobile.getInheritedTheme( this.element, "c" ),
7683 theme = this.options.theme || parentTheme,
7684 trackTheme = this.options.trackTheme || parentTheme,
7685 left, width, data, tol;
7686
7687 self.slider[0].className = [ this.isToggleSwitch ? "ui-slider ui-slider-switch" : "ui-slider-track"," ui-btn-down-" + trackTheme,' ui-btn-corner-all', ( this.options.mini ) ? " ui-mini":""].join( "" );
7688 if ( this.options.disabled || this.element.attr( "disabled" ) ) {
7689 this.disable();
7690 }
7691
7692 // set the stored value for comparison later
7693 this.value = this._value();
7694 if ( this.options.highlight && !this.isToggleSwitch && this.slider.find( ".ui-slider-bg" ).length === 0 ) {
7695 this.valuebg = (function() {
7696 var bg = document.createElement( "div" );
7697 bg.className = "ui-slider-bg " + $.mobile.activeBtnClass + " ui-btn-corner-all";
7698 return $( bg ).prependTo( self.slider );
7699 })();
7700 }
7701 this.handle.buttonMarkup({ corners: true, theme: theme, shadow: true });
7702
7703 var pxStep, percent,
7704 control = this.element,
7705 isInput = !this.isToggleSwitch,
7706 optionElements = isInput ? [] : control.find( "option" ),
7707 min = isInput ? parseFloat( control.attr( "min" ) ) : 0,
7708 max = isInput ? parseFloat( control.attr( "max" ) ) : optionElements.length - 1,
7709 step = ( isInput && parseFloat( control.attr( "step" ) ) > 0 ) ? parseFloat( control.attr( "step" ) ) : 1;
7710
7711 if ( typeof val === "object" ) {
7712 data = val;
7713 // a slight tolerance helped get to the ends of the slider
7714 tol = 8;
7715
7716 left = this.slider.offset().left;
7717 width = this.slider.width();
7718 pxStep = width/((max-min)/step);
7719 if ( !this.dragging ||
7720 data.pageX < left - tol ||
7721 data.pageX > left + width + tol ) {
7722 return;
7723 }
7724 if ( pxStep > 1 ) {
7725 percent = ( ( data.pageX - left ) / width ) * 100;
7726 } else {
7727 percent = Math.round( ( ( data.pageX - left ) / width ) * 100 );
7728 }
7729 } else {
7730 if ( val == null ) {
7731 val = isInput ? parseFloat( control.val() || 0 ) : control[0].selectedIndex;
7732 }
7733 percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
7734 }
7735
7736 if ( isNaN( percent ) ) {
7737 return;
7738 }
7739
7740 var newval = ( percent / 100 ) * ( max - min ) + min;
7741
7742 //from jQuery UI slider, the following source will round to the nearest step
7743 var valModStep = ( newval - min ) % step;
7744 var alignValue = newval - valModStep;
7745
7746 if ( Math.abs( valModStep ) * 2 >= step ) {
7747 alignValue += ( valModStep > 0 ) ? step : ( -step );
7748 }
7749
7750 var percentPerStep = 100/((max-min)/step);
7751 // Since JavaScript has problems with large floats, round
7752 // the final value to 5 digits after the decimal point (see jQueryUI: #4124)
7753 newval = parseFloat( alignValue.toFixed(5) );
7754
7755 if ( typeof pxStep === "undefined" ) {
7756 pxStep = width / ( (max-min) / step );
7757 }
7758 if ( pxStep > 1 && isInput ) {
7759 percent = ( newval - min ) * percentPerStep * ( 1 / step );
7760 }
7761 if ( percent < 0 ) {
7762 percent = 0;
7763 }
7764
7765 if ( percent > 100 ) {
7766 percent = 100;
7767 }
7768
7769 if ( newval < min ) {
7770 newval = min;
7771 }
7772
7773 if ( newval > max ) {
7774 newval = max;
7775 }
7776
7777 this.handle.css( "left", percent + "%" );
7778
7779 this.handle[0].setAttribute( "aria-valuenow", isInput ? newval : optionElements.eq( newval ).attr( "value" ) );
7780
7781 this.handle[0].setAttribute( "aria-valuetext", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
7782
7783 this.handle[0].setAttribute( "title", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
7784
7785 if ( this.valuebg ) {
7786 this.valuebg.css( "width", percent + "%" );
7787 }
7788
7789 // drag the label widths
7790 if ( this._labels ) {
7791 var handlePercent = this.handle.width() / this.slider.width() * 100,
7792 aPercent = percent && handlePercent + ( 100 - handlePercent ) * percent / 100,
7793 bPercent = percent === 100 ? 0 : Math.min( handlePercent + 100 - aPercent, 100 );
7794
7795 this._labels.each(function() {
7796 var ab = $( this ).is( ".ui-slider-label-a" );
7797 $( this ).width( ( ab ? aPercent : bPercent ) + "%" );
7798 });
7799 }
7800
7801 if ( !preventInputUpdate ) {
7802 var valueChanged = false;
7803
7804 // update control"s value
7805 if ( isInput ) {
7806 valueChanged = control.val() !== newval;
7807 control.val( newval );
7808 } else {
7809 valueChanged = control[ 0 ].selectedIndex !== newval;
7810 control[ 0 ].selectedIndex = newval;
7811 }
7812 if ( this._trigger( "beforechange", val ) === false) {
7813 return false;
7814 }
7815 if ( !isfromControl && valueChanged ) {
7816 control.trigger( "change" );
7817 }
7818 }
7819 },
7820
7821 enable: function() {
7822 this.element.attr( "disabled", false );
7823 this.slider.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
7824 return this._setOption( "disabled", false );
7825 },
7826
7827 disable: function() {
7828 this.element.attr( "disabled", true );
7829 this.slider.addClass( "ui-disabled" ).attr( "aria-disabled", true );
7830 return this._setOption( "disabled", true );
7831 }
7832
7833}, $.mobile.behaviors.formReset ) );
7834
7835//auto self-init widgets
7836$.mobile.document.bind( "pagecreate create", function( e ) {
7837 $.mobile.slider.prototype.enhanceWithin( e.target, true );
7838});
7839
7840})( jQuery );
7841
7842(function( $, undefined ) {
7843 $.widget( "mobile.rangeslider", $.mobile.widget, {
7844
7845 options: {
7846 theme: null,
7847 trackTheme: null,
7848 disabled: false,
7849 initSelector: ":jqmData(role='rangeslider')",
7850 mini: false,
7851 highlight: true
7852 },
7853
7854 _create: function() {
7855 var secondLabel,
7856 $el = this.element,
7857 elClass = this.options.mini ? "ui-rangeslider ui-mini" : "ui-rangeslider",
7858 _inputFirst = $el.find( "input" ).first(),
7859 _inputLast = $el.find( "input" ).last(),
7860 label = $el.find( "label" ).first(),
7861 _sliderFirst = $.data( _inputFirst.get(0), "mobileSlider" ).slider,
7862 _sliderLast = $.data( _inputLast.get(0), "mobileSlider" ).slider,
7863 firstHandle = $.data( _inputFirst.get(0), "mobileSlider" ).handle,
7864 _sliders = $( "<div class=\"ui-rangeslider-sliders\" />" ).appendTo( $el );
7865
7866 if ( $el.find( "label" ).length > 1 ) {
7867 secondLabel = $el.find( "label" ).last().hide();
7868 }
7869
7870 _inputFirst.addClass( "ui-rangeslider-first" );
7871 _inputLast.addClass( "ui-rangeslider-last" );
7872 $el.addClass( elClass );
7873
7874 _sliderFirst.appendTo( _sliders );
7875 _sliderLast.appendTo( _sliders );
7876 label.prependTo( $el );
7877 firstHandle.prependTo( _sliderLast );
7878
7879 $.extend( this, {
7880 _inputFirst: _inputFirst,
7881 _inputLast: _inputLast,
7882 _sliderFirst: _sliderFirst,
7883 _sliderLast: _sliderLast,
7884 _targetVal: null,
7885 _sliderTarget: false,
7886 _sliders: _sliders,
7887 _proxy: false
7888 });
7889
7890 this.refresh();
7891 this._on( this.element.find( "input.ui-slider-input" ), {
7892 "slidebeforestart": "_slidebeforestart",
7893 "slidestop": "_slidestop",
7894 "slidedrag": "_slidedrag",
7895 "slidebeforechange": "_change",
7896 "blur": "_change",
7897 "keyup": "_change"
7898 });
7899 this._on({
7900 "mousedown":"_change"
7901 });
7902 this._on( this.element.closest( "form" ), {
7903 "reset":"_handleReset"
7904 });
7905 this._on( firstHandle, {
7906 "vmousedown": "_dragFirstHandle"
7907 });
7908 },
7909 _handleReset: function(){
7910 var self = this;
7911 //we must wait for the stack to unwind before updateing other wise sliders will not have updated yet
7912 setTimeout( function(){
7913 self._updateHighlight();
7914 },0);
7915 },
7916
7917 _dragFirstHandle: function( event ) {
7918 //if the first handle is dragged send the event to the first slider
7919 $.data( this._inputFirst.get(0), "mobileSlider" ).dragging = true;
7920 $.data( this._inputFirst.get(0), "mobileSlider" ).refresh( event );
7921 return false;
7922 },
7923
7924 _slidedrag: function( event ) {
7925 var first = $( event.target ).is( this._inputFirst ),
7926 otherSlider = ( first ) ? this._inputLast : this._inputFirst;
7927
7928 this._sliderTarget = false;
7929 //if the drag was initiated on an extreme and the other handle is focused send the events to
7930 //the closest handle
7931 if ( ( this._proxy === "first" && first ) || ( this._proxy === "last" && !first ) ) {
7932 $.data( otherSlider.get(0), "mobileSlider" ).dragging = true;
7933 $.data( otherSlider.get(0), "mobileSlider" ).refresh( event );
7934 return false;
7935 }
7936 },
7937
7938 _slidestop: function( event ) {
7939 var first = $( event.target ).is( this._inputFirst );
7940
7941 this._proxy = false;
7942 //this stops dragging of the handle and brings the active track to the front
7943 //this makes clicks on the track go the the last handle used
7944 this.element.find( "input" ).trigger( "vmouseup" );
7945 this._sliderFirst.css( "z-index", first ? 1 : "" );
7946 },
7947
7948 _slidebeforestart: function( event ) {
7949 this._sliderTarget = false;
7950 //if the track is the target remember this and the original value
7951 if ( $( event.originalEvent.target ).hasClass( "ui-slider-track" ) ) {
7952 this._sliderTarget = true;
7953 this._targetVal = $( event.target ).val();
7954 }
7955 },
7956
7957 _setOption: function( options ) {
7958 this._superApply( options );
7959 this.refresh();
7960 },
7961
7962 refresh: function() {
7963 var $el = this.element,
7964 o = this.options;
7965
7966 $el.find( "input" ).slider({
7967 theme: o.theme,
7968 trackTheme: o.trackTheme,
7969 disabled: o.disabled,
7970 mini: o.mini,
7971 highlight: o.highlight
7972 }).slider( "refresh" );
7973 this._updateHighlight();
7974 },
7975
7976 _change: function( event ) {
7977 if ( event.type === "keyup" ) {
7978 this._updateHighlight();
7979 return false;
7980 }
7981
7982 var self = this,
7983 min = parseFloat( this._inputFirst.val(), 10 ),
7984 max = parseFloat( this._inputLast.val(), 10 ),
7985 first = $( event.target ).hasClass( "ui-rangeslider-first" ),
7986 thisSlider = first ? this._inputFirst : this._inputLast,
7987 otherSlider = first ? this._inputLast : this._inputFirst;
7988
7989
7990 if( ( this._inputFirst.val() > this._inputLast.val() && event.type === "mousedown" && !$(event.target).hasClass("ui-slider-handle")) ){
7991 thisSlider.blur();
7992 } else if( event.type === "mousedown" ){
7993 return;
7994 }
7995 if ( min > max && !this._sliderTarget ) {
7996 //this prevents min from being greater then max
7997 thisSlider.val( first ? max: min ).slider( "refresh" );
7998 this._trigger( "normalize" );
7999 } else if ( min > max ) {
8000 //this makes it so clicks on the target on either extreme go to the closest handle
8001 thisSlider.val( this._targetVal ).slider( "refresh" );
8002
8003 //You must wait for the stack to unwind so first slider is updated before updating second
8004 setTimeout( function() {
8005 otherSlider.val( first ? min: max ).slider( "refresh" );
8006 $.data( otherSlider.get(0), "mobileSlider" ).handle.focus();
8007 self._sliderFirst.css( "z-index", first ? "" : 1 );
8008 self._trigger( "normalize" );
8009 }, 0 );
8010 this._proxy = ( first ) ? "first" : "last";
8011 }
8012 //fixes issue where when both _sliders are at min they cannot be adjusted
8013 if ( min === max ) {
8014 $.data( thisSlider.get(0), "mobileSlider" ).handle.css( "z-index", 1 );
8015 $.data( otherSlider.get(0), "mobileSlider" ).handle.css( "z-index", 0 );
8016 } else {
8017 $.data( otherSlider.get(0), "mobileSlider" ).handle.css( "z-index", "" );
8018 $.data( thisSlider.get(0), "mobileSlider" ).handle.css( "z-index", "" );
8019 }
8020
8021 this._updateHighlight();
8022
8023 if ( min >= max ) {
8024 return false;
8025 }
8026 },
8027
8028 _updateHighlight: function() {
8029 var min = parseInt( $.data( this._inputFirst.get(0), "mobileSlider" ).handle.get(0).style.left, 10 ),
8030 max = parseInt( $.data( this._inputLast.get(0), "mobileSlider" ).handle.get(0).style.left, 10 ),
8031 width = (max - min);
8032
8033 this.element.find( ".ui-slider-bg" ).css({
8034 "margin-left": min + "%",
8035 "width": width + "%"
8036 });
8037 },
8038
8039 _destroy: function() {
8040 this.element.removeClass( "ui-rangeslider ui-mini" ).find( "label" ).show();
8041 this._inputFirst.after( this._sliderFirst );
8042 this._inputLast.after( this._sliderLast );
8043 this._sliders.remove();
8044 this.element.find( "input" ).removeClass( "ui-rangeslider-first ui-rangeslider-last" ).slider( "destroy" );
8045 }
8046
8047 });
8048
8049$.widget( "mobile.rangeslider", $.mobile.rangeslider, $.mobile.behaviors.formReset );
8050
8051//auto self-init widgets
8052$( document ).bind( "pagecreate create", function( e ) {
8053 $.mobile.rangeslider.prototype.enhanceWithin( e.target, true );
8054});
8055
8056})( jQuery );
8057
8058(function( $, undefined ) {
8059
8060$.widget( "mobile.selectmenu", $.mobile.widget, $.extend( {
8061 options: {
8062 theme: null,
8063 disabled: false,
8064 icon: "arrow-d",
8065 iconpos: "right",
8066 inline: false,
8067 corners: true,
8068 shadow: true,
8069 iconshadow: true,
8070 overlayTheme: "a",
8071 dividerTheme: "b",
8072 hidePlaceholderMenuItems: true,
8073 closeText: "Close",
8074 nativeMenu: true,
8075 // This option defaults to true on iOS devices.
8076 preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
8077 initSelector: "select:not( :jqmData(role='slider') )",
8078 mini: false
8079 },
8080
8081 _button: function() {
8082 return $( "<div/>" );
8083 },
8084
8085 _setDisabled: function( value ) {
8086 this.element.attr( "disabled", value );
8087 this.button.attr( "aria-disabled", value );
8088 return this._setOption( "disabled", value );
8089 },
8090
8091 _focusButton : function() {
8092 var self = this;
8093
8094 setTimeout( function() {
8095 self.button.focus();
8096 }, 40);
8097 },
8098
8099 _selectOptions: function() {
8100 return this.select.find( "option" );
8101 },
8102
8103 // setup items that are generally necessary for select menu extension
8104 _preExtension: function() {
8105 var classes = "";
8106 // 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
8107 /* if ( $el[0].className.length ) {
8108 classes = $el[0].className;
8109 } */
8110 if ( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
8111 classes = " ui-btn-left";
8112 }
8113
8114 if ( !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
8115 classes = " ui-btn-right";
8116 }
8117
8118 this.select = this.element.removeClass( "ui-btn-left ui-btn-right" ).wrap( "<div class='ui-select" + classes + "'>" );
8119 this.selectID = this.select.attr( "id" );
8120 this.label = $( "label[for='"+ this.selectID +"']" ).addClass( "ui-select" );
8121 this.isMultiple = this.select[ 0 ].multiple;
8122 if ( !this.options.theme ) {
8123 this.options.theme = $.mobile.getInheritedTheme( this.select, "c" );
8124 }
8125 },
8126
8127 _destroy: function() {
8128 var wrapper = this.element.parents( ".ui-select" );
8129 if ( wrapper.length > 0 ) {
8130 if ( wrapper.is( ".ui-btn-left, .ui-btn-right" ) ) {
8131 this.element.addClass( wrapper.is( ".ui-btn-left" ) ? "ui-btn-left" : "ui-btn-right" );
8132 }
8133 this.element.insertAfter( wrapper );
8134 wrapper.remove();
8135 }
8136 },
8137
8138 _create: function() {
8139 this._preExtension();
8140
8141 // Allows for extension of the native select for custom selects and other plugins
8142 // see select.custom for example extension
8143 // TODO explore plugin registration
8144 this._trigger( "beforeCreate" );
8145
8146 this.button = this._button();
8147
8148 var self = this,
8149
8150 options = this.options,
8151
8152 inline = options.inline || this.select.jqmData( "inline" ),
8153 mini = options.mini || this.select.jqmData( "mini" ),
8154 iconpos = options.icon ? ( options.iconpos || this.select.jqmData( "iconpos" ) ) : false,
8155
8156 // IE throws an exception at options.item() function when
8157 // there is no selected item
8158 // select first in this case
8159 selectedIndex = this.select[ 0 ].selectedIndex === -1 ? 0 : this.select[ 0 ].selectedIndex,
8160
8161 // TODO values buttonId and menuId are undefined here
8162 button = this.button
8163 .insertBefore( this.select )
8164 .buttonMarkup( {
8165 theme: options.theme,
8166 icon: options.icon,
8167 iconpos: iconpos,
8168 inline: inline,
8169 corners: options.corners,
8170 shadow: options.shadow,
8171 iconshadow: options.iconshadow,
8172 mini: mini
8173 });
8174
8175 this.setButtonText();
8176
8177 // Opera does not properly support opacity on select elements
8178 // In Mini, it hides the element, but not its text
8179 // On the desktop,it seems to do the opposite
8180 // for these reasons, using the nativeMenu option results in a full native select in Opera
8181 if ( options.nativeMenu && window.opera && window.opera.version ) {
8182 button.addClass( "ui-select-nativeonly" );
8183 }
8184
8185 // Add counter for multi selects
8186 if ( this.isMultiple ) {
8187 this.buttonCount = $( "<span>" )
8188 .addClass( "ui-li-count ui-btn-up-c ui-btn-corner-all" )
8189 .hide()
8190 .appendTo( button.addClass('ui-li-has-count') );
8191 }
8192
8193 // Disable if specified
8194 if ( options.disabled || this.element.attr('disabled')) {
8195 this.disable();
8196 }
8197
8198 // Events on native select
8199 this.select.change(function() {
8200 self.refresh();
8201
8202 if ( !!options.nativeMenu ) {
8203 this.blur();
8204 }
8205 });
8206
8207 this._handleFormReset();
8208
8209 this.build();
8210 },
8211
8212 build: function() {
8213 var self = this;
8214
8215 this.select
8216 .appendTo( self.button )
8217 .bind( "vmousedown", function() {
8218 // Add active class to button
8219 self.button.addClass( $.mobile.activeBtnClass );
8220 })
8221 .bind( "focus", function() {
8222 self.button.addClass( $.mobile.focusClass );
8223 })
8224 .bind( "blur", function() {
8225 self.button.removeClass( $.mobile.focusClass );
8226 })
8227 .bind( "focus vmouseover", function() {
8228 self.button.trigger( "vmouseover" );
8229 })
8230 .bind( "vmousemove", function() {
8231 // Remove active class on scroll/touchmove
8232 self.button.removeClass( $.mobile.activeBtnClass );
8233 })
8234 .bind( "change blur vmouseout", function() {
8235 self.button.trigger( "vmouseout" )
8236 .removeClass( $.mobile.activeBtnClass );
8237 })
8238 .bind( "change blur", function() {
8239 self.button.removeClass( "ui-btn-down-" + self.options.theme );
8240 });
8241
8242 // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
8243 self.button.bind( "vmousedown", function() {
8244 if ( self.options.preventFocusZoom ) {
8245 $.mobile.zoom.disable( true );
8246 }
8247 });
8248 self.label.bind( "click focus", function() {
8249 if ( self.options.preventFocusZoom ) {
8250 $.mobile.zoom.disable( true );
8251 }
8252 });
8253 self.select.bind( "focus", function() {
8254 if ( self.options.preventFocusZoom ) {
8255 $.mobile.zoom.disable( true );
8256 }
8257 });
8258 self.button.bind( "mouseup", function() {
8259 if ( self.options.preventFocusZoom ) {
8260 setTimeout(function() {
8261 $.mobile.zoom.enable( true );
8262 }, 0 );
8263 }
8264 });
8265 self.select.bind( "blur", function() {
8266 if ( self.options.preventFocusZoom ) {
8267 $.mobile.zoom.enable( true );
8268 }
8269 });
8270
8271 },
8272
8273 selected: function() {
8274 return this._selectOptions().filter( ":selected" );
8275 },
8276
8277 selectedIndices: function() {
8278 var self = this;
8279
8280 return this.selected().map(function() {
8281 return self._selectOptions().index( this );
8282 }).get();
8283 },
8284
8285 setButtonText: function() {
8286 var self = this,
8287 selected = this.selected(),
8288 text = this.placeholder,
8289 span = $( document.createElement( "span" ) );
8290
8291 this.button.find( ".ui-btn-text" ).html(function() {
8292 if ( selected.length ) {
8293 text = selected.map(function() {
8294 return $( this ).text();
8295 }).get().join( ", " );
8296 } else {
8297 text = self.placeholder;
8298 }
8299
8300 // TODO possibly aggregate multiple select option classes
8301 return span.text( text )
8302 .addClass( self.select.attr( "class" ) )
8303 .addClass( selected.attr( "class" ) );
8304 });
8305 },
8306
8307 setButtonCount: function() {
8308 var selected = this.selected();
8309
8310 // multiple count inside button
8311 if ( this.isMultiple ) {
8312 this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
8313 }
8314 },
8315
8316 _reset: function() {
8317 this.refresh();
8318 },
8319
8320 refresh: function() {
8321 this.setButtonText();
8322 this.setButtonCount();
8323 },
8324
8325 // open and close preserved in native selects
8326 // to simplify users code when looping over selects
8327 open: $.noop,
8328 close: $.noop,
8329
8330 disable: function() {
8331 this._setDisabled( true );
8332 this.button.addClass( "ui-disabled" );
8333 },
8334
8335 enable: function() {
8336 this._setDisabled( false );
8337 this.button.removeClass( "ui-disabled" );
8338 }
8339}, $.mobile.behaviors.formReset ) );
8340
8341//auto self-init widgets
8342$.mobile.document.bind( "pagecreate create", function( e ) {
8343 $.mobile.selectmenu.prototype.enhanceWithin( e.target, true );
8344});
8345})( jQuery );
8346
8347(function( $, undefined ) {
8348
8349function fitSegmentInsideSegment( winSize, segSize, offset, desired ) {
8350 var ret = desired;
8351
8352 if ( winSize < segSize ) {
8353 // Center segment if it's bigger than the window
8354 ret = offset + ( winSize - segSize ) / 2;
8355 } else {
8356 // Otherwise center it at the desired coordinate while keeping it completely inside the window
8357 ret = Math.min( Math.max( offset, desired - segSize / 2 ), offset + winSize - segSize );
8358 }
8359
8360 return ret;
8361}
8362
8363function windowCoords() {
8364 var $win = $.mobile.window;
8365
8366 return {
8367 x: $win.scrollLeft(),
8368 y: $win.scrollTop(),
8369 cx: ( window.innerWidth || $win.width() ),
8370 cy: ( window.innerHeight || $win.height() )
8371 };
8372}
8373
8374$.widget( "mobile.popup", $.mobile.widget, {
8375 options: {
8376 theme: null,
8377 overlayTheme: null,
8378 shadow: true,
8379 corners: true,
8380 transition: "none",
8381 positionTo: "origin",
8382 tolerance: null,
8383 initSelector: ":jqmData(role='popup')",
8384 closeLinkSelector: "a:jqmData(rel='back')",
8385 closeLinkEvents: "click.popup",
8386 navigateEvents: "navigate.popup",
8387 closeEvents: "navigate.popup pagebeforechange.popup",
8388 dismissible: true,
8389
8390 // NOTE Windows Phone 7 has a scroll position caching issue that
8391 // requires us to disable popup history management by default
8392 // https://github.com/jquery/jquery-mobile/issues/4784
8393 //
8394 // NOTE this option is modified in _create!
8395 history: !$.mobile.browser.oldIE
8396 },
8397
8398 _eatEventAndClose: function( e ) {
8399 e.preventDefault();
8400 e.stopImmediatePropagation();
8401 if ( this.options.dismissible ) {
8402 this.close();
8403 }
8404 return false;
8405 },
8406
8407 // Make sure the screen size is increased beyond the page height if the popup's causes the document to increase in height
8408 _resizeScreen: function() {
8409 var popupHeight = this._ui.container.outerHeight( true );
8410
8411 this._ui.screen.removeAttr( "style" );
8412 if ( popupHeight > this._ui.screen.height() ) {
8413 this._ui.screen.height( popupHeight );
8414 }
8415 },
8416
8417 _handleWindowKeyUp: function( e ) {
8418 if ( this._isOpen && e.keyCode === $.mobile.keyCode.ESCAPE ) {
8419 return this._eatEventAndClose( e );
8420 }
8421 },
8422
8423 _expectResizeEvent: function() {
8424 var winCoords = windowCoords();
8425
8426 if ( this._resizeData ) {
8427 if ( winCoords.x === this._resizeData.winCoords.x &&
8428 winCoords.y === this._resizeData.winCoords.y &&
8429 winCoords.cx === this._resizeData.winCoords.cx &&
8430 winCoords.cy === this._resizeData.winCoords.cy ) {
8431 // timeout not refreshed
8432 return false;
8433 } else {
8434 // clear existing timeout - it will be refreshed below
8435 clearTimeout( this._resizeData.timeoutId );
8436 }
8437 }
8438
8439 this._resizeData = {
8440 timeoutId: setTimeout( $.proxy( this, "_resizeTimeout" ), 200 ),
8441 winCoords: winCoords
8442 };
8443
8444 return true;
8445 },
8446
8447 _resizeTimeout: function() {
8448 if ( this._isOpen ) {
8449 if ( !this._expectResizeEvent() ) {
8450 if ( this._ui.container.hasClass( "ui-popup-hidden" ) ) {
8451 // effectively rapid-open the popup while leaving the screen intact
8452 this._ui.container.removeClass( "ui-popup-hidden" );
8453 this.reposition( { positionTo: "window" } );
8454 this._ignoreResizeEvents();
8455 }
8456
8457 this._resizeScreen();
8458 this._resizeData = null;
8459 this._orientationchangeInProgress = false;
8460 }
8461 } else {
8462 this._resizeData = null;
8463 this._orientationchangeInProgress = false;
8464 }
8465 },
8466
8467 _ignoreResizeEvents: function() {
8468 var self = this;
8469
8470 if ( this._ignoreResizeTo ) {
8471 clearTimeout( this._ignoreResizeTo );
8472 }
8473 this._ignoreResizeTo = setTimeout( function() { self._ignoreResizeTo = 0; }, 1000 );
8474 },
8475
8476 _handleWindowResize: function( e ) {
8477 if ( this._isOpen && this._ignoreResizeTo === 0 ) {
8478 if ( ( this._expectResizeEvent() || this._orientationchangeInProgress ) &&
8479 !this._ui.container.hasClass( "ui-popup-hidden" ) ) {
8480 // effectively rapid-close the popup while leaving the screen intact
8481 this._ui.container
8482 .addClass( "ui-popup-hidden" )
8483 .removeAttr( "style" );
8484 }
8485 }
8486 },
8487
8488 _handleWindowOrientationchange: function( e ) {
8489 if ( !this._orientationchangeInProgress && this._isOpen && this._ignoreResizeTo === 0 ) {
8490 this._expectResizeEvent();
8491 this._orientationchangeInProgress = true;
8492 }
8493 },
8494
8495 // When the popup is open, attempting to focus on an element that is not a
8496 // child of the popup will redirect focus to the popup
8497 _handleDocumentFocusIn: function( e ) {
8498 var tgt = e.target, $tgt, ui = this._ui;
8499
8500 if ( !this._isOpen ) {
8501 return;
8502 }
8503
8504 if ( tgt !== ui.container[ 0 ] ) {
8505 $tgt = $( e.target );
8506 if ( 0 === $tgt.parents().filter( ui.container[ 0 ] ).length ) {
8507 $( document.activeElement ).one( "focus", function( e ) {
8508 $tgt.blur();
8509 });
8510 ui.focusElement.focus();
8511 e.preventDefault();
8512 e.stopImmediatePropagation();
8513 return false;
8514 } else if ( ui.focusElement[ 0 ] === ui.container[ 0 ] ) {
8515 ui.focusElement = $tgt;
8516 }
8517 }
8518
8519 this._ignoreResizeEvents();
8520 },
8521
8522 _create: function() {
8523 var ui = {
8524 screen: $( "<div class='ui-screen-hidden ui-popup-screen'></div>" ),
8525 placeholder: $( "<div style='display: none;'><!-- placeholder --></div>" ),
8526 container: $( "<div class='ui-popup-container ui-popup-hidden'></div>" )
8527 },
8528 thisPage = this.element.closest( ".ui-page" ),
8529 myId = this.element.attr( "id" ),
8530 o = this.options,
8531 key, value;
8532
8533 // We need to adjust the history option to be false if there's no AJAX nav.
8534 // We can't do it in the option declarations because those are run before
8535 // it is determined whether there shall be AJAX nav.
8536 o.history = o.history && $.mobile.ajaxEnabled && $.mobile.hashListeningEnabled;
8537
8538 if ( thisPage.length === 0 ) {
8539 thisPage = $( "body" );
8540 }
8541
8542 // define the container for navigation event bindings
8543 // TODO this would be nice at the the mobile widget level
8544 o.container = o.container || $.mobile.pageContainer || thisPage;
8545
8546 // Apply the proto
8547 thisPage.append( ui.screen );
8548 ui.container.insertAfter( ui.screen );
8549 // Leave a placeholder where the element used to be
8550 ui.placeholder.insertAfter( this.element );
8551 if ( myId ) {
8552 ui.screen.attr( "id", myId + "-screen" );
8553 ui.container.attr( "id", myId + "-popup" );
8554 ui.placeholder.html( "<!-- placeholder for " + myId + " -->" );
8555 }
8556 ui.container.append( this.element );
8557 ui.focusElement = ui.container;
8558
8559 // Add class to popup element
8560 this.element.addClass( "ui-popup" );
8561
8562 // Define instance variables
8563 $.extend( this, {
8564 _scrollTop: 0,
8565 _page: thisPage,
8566 _ui: ui,
8567 _fallbackTransition: "",
8568 _currentTransition: false,
8569 _prereqs: null,
8570 _isOpen: false,
8571 _tolerance: null,
8572 _resizeData: null,
8573 _ignoreResizeTo: 0,
8574 _orientationchangeInProgress: false
8575 });
8576
8577 // This duplicates the code from the various option setters below for
8578 // better performance. It must be kept in sync with those setters.
8579 this._applyTheme( this.element, o.theme, "body" );
8580 this._applyTheme( this._ui.screen, o.overlayTheme, "overlay" );
8581 this._applyTransition( o.transition );
8582 this.element
8583 .toggleClass( "ui-overlay-shadow", o.shadow )
8584 .toggleClass( "ui-corner-all", o.corners );
8585 this._setTolerance( o.tolerance );
8586
8587 ui.screen.bind( "vclick", $.proxy( this, "_eatEventAndClose" ) );
8588
8589 this._on( $.mobile.window, {
8590 orientationchange: $.proxy( this, "_handleWindowOrientationchange" ),
8591 resize: $.proxy( this, "_handleWindowResize" ),
8592 keyup: $.proxy( this, "_handleWindowKeyUp" )
8593 });
8594 this._on( $.mobile.document, {
8595 focusin: $.proxy( this, "_handleDocumentFocusIn" )
8596 });
8597 },
8598
8599 _applyTheme: function( dst, theme, prefix ) {
8600 var classes = ( dst.attr( "class" ) || "").split( " " ),
8601 alreadyAdded = true,
8602 currentTheme = null,
8603 matches,
8604 themeStr = String( theme );
8605
8606 while ( classes.length > 0 ) {
8607 currentTheme = classes.pop();
8608 matches = ( new RegExp( "^ui-" + prefix + "-([a-z])$" ) ).exec( currentTheme );
8609 if ( matches && matches.length > 1 ) {
8610 currentTheme = matches[ 1 ];
8611 break;
8612 } else {
8613 currentTheme = null;
8614 }
8615 }
8616
8617 if ( theme !== currentTheme ) {
8618 dst.removeClass( "ui-" + prefix + "-" + currentTheme );
8619 if ( ! ( theme === null || theme === "none" ) ) {
8620 dst.addClass( "ui-" + prefix + "-" + themeStr );
8621 }
8622 }
8623 },
8624
8625 _setTheme: function( value ) {
8626 this._applyTheme( this.element, value, "body" );
8627 },
8628
8629 _setOverlayTheme: function( value ) {
8630 this._applyTheme( this._ui.screen, value, "overlay" );
8631
8632 if ( this._isOpen ) {
8633 this._ui.screen.addClass( "in" );
8634 }
8635 },
8636
8637 _setShadow: function( value ) {
8638 this.element.toggleClass( "ui-overlay-shadow", value );
8639 },
8640
8641 _setCorners: function( value ) {
8642 this.element.toggleClass( "ui-corner-all", value );
8643 },
8644
8645 _applyTransition: function( value ) {
8646 this._ui.container.removeClass( this._fallbackTransition );
8647 if ( value && value !== "none" ) {
8648 this._fallbackTransition = $.mobile._maybeDegradeTransition( value );
8649 if ( this._fallbackTransition === "none" ) {
8650 this._fallbackTransition = "";
8651 }
8652 this._ui.container.addClass( this._fallbackTransition );
8653 }
8654 },
8655
8656 _setTransition: function( value ) {
8657 if ( !this._currentTransition ) {
8658 this._applyTransition( value );
8659 }
8660 },
8661
8662 _setTolerance: function( value ) {
8663 var tol = { t: 30, r: 15, b: 30, l: 15 };
8664
8665 if ( value !== undefined ) {
8666 var ar = String( value ).split( "," );
8667
8668 $.each( ar, function( idx, val ) { ar[ idx ] = parseInt( val, 10 ); } );
8669
8670 switch( ar.length ) {
8671 // All values are to be the same
8672 case 1:
8673 if ( !isNaN( ar[ 0 ] ) ) {
8674 tol.t = tol.r = tol.b = tol.l = ar[ 0 ];
8675 }
8676 break;
8677
8678 // The first value denotes top/bottom tolerance, and the second value denotes left/right tolerance
8679 case 2:
8680 if ( !isNaN( ar[ 0 ] ) ) {
8681 tol.t = tol.b = ar[ 0 ];
8682 }
8683 if ( !isNaN( ar[ 1 ] ) ) {
8684 tol.l = tol.r = ar[ 1 ];
8685 }
8686 break;
8687
8688 // The array contains values in the order top, right, bottom, left
8689 case 4:
8690 if ( !isNaN( ar[ 0 ] ) ) {
8691 tol.t = ar[ 0 ];
8692 }
8693 if ( !isNaN( ar[ 1 ] ) ) {
8694 tol.r = ar[ 1 ];
8695 }
8696 if ( !isNaN( ar[ 2 ] ) ) {
8697 tol.b = ar[ 2 ];
8698 }
8699 if ( !isNaN( ar[ 3 ] ) ) {
8700 tol.l = ar[ 3 ];
8701 }
8702 break;
8703
8704 default:
8705 break;
8706 }
8707 }
8708
8709 this._tolerance = tol;
8710 },
8711
8712 _setOption: function( key, value ) {
8713 var setter = "_set" + key.charAt( 0 ).toUpperCase() + key.slice( 1 );
8714
8715 if ( this[ setter ] !== undefined ) {
8716 this[ setter ]( value );
8717 }
8718
8719 this._super( key, value );
8720 },
8721
8722 // Try and center the overlay over the given coordinates
8723 _placementCoords: function( desired ) {
8724 // rectangle within which the popup must fit
8725 var
8726 winCoords = windowCoords(),
8727 rc = {
8728 x: this._tolerance.l,
8729 y: winCoords.y + this._tolerance.t,
8730 cx: winCoords.cx - this._tolerance.l - this._tolerance.r,
8731 cy: winCoords.cy - this._tolerance.t - this._tolerance.b
8732 },
8733 menuSize, ret;
8734
8735 // Clamp the width of the menu before grabbing its size
8736 this._ui.container.css( "max-width", rc.cx );
8737 menuSize = {
8738 cx: this._ui.container.outerWidth( true ),
8739 cy: this._ui.container.outerHeight( true )
8740 };
8741
8742 // Center the menu over the desired coordinates, while not going outside
8743 // the window tolerances. This will center wrt. the window if the popup is too large.
8744 ret = {
8745 x: fitSegmentInsideSegment( rc.cx, menuSize.cx, rc.x, desired.x ),
8746 y: fitSegmentInsideSegment( rc.cy, menuSize.cy, rc.y, desired.y )
8747 };
8748
8749 // Make sure the top of the menu is visible
8750 ret.y = Math.max( 0, ret.y );
8751
8752 // If the height of the menu is smaller than the height of the document
8753 // align the bottom with the bottom of the document
8754
8755 // fix for $.mobile.document.height() bug in core 1.7.2.
8756 var docEl = document.documentElement, docBody = document.body,
8757 docHeight = Math.max( docEl.clientHeight, docBody.scrollHeight, docBody.offsetHeight, docEl.scrollHeight, docEl.offsetHeight );
8758
8759 ret.y -= Math.min( ret.y, Math.max( 0, ret.y + menuSize.cy - docHeight ) );
8760
8761 return { left: ret.x, top: ret.y };
8762 },
8763
8764 _createPrereqs: function( screenPrereq, containerPrereq, whenDone ) {
8765 var self = this, prereqs;
8766
8767 // It is important to maintain both the local variable prereqs and self._prereqs. The local variable remains in
8768 // the closure of the functions which call the callbacks passed in. The comparison between the local variable and
8769 // self._prereqs is necessary, because once a function has been passed to .animationComplete() it will be called
8770 // next time an animation completes, even if that's not the animation whose end the function was supposed to catch
8771 // (for example, if an abort happens during the opening animation, the .animationComplete handler is not called for
8772 // that animation anymore, but the handler remains attached, so it is called the next time the popup is opened
8773 // - making it stale. Comparing the local variable prereqs to the widget-level variable self._prereqs ensures that
8774 // callbacks triggered by a stale .animationComplete will be ignored.
8775
8776 prereqs = {
8777 screen: $.Deferred(),
8778 container: $.Deferred()
8779 };
8780
8781 prereqs.screen.then( function() {
8782 if ( prereqs === self._prereqs ) {
8783 screenPrereq();
8784 }
8785 });
8786
8787 prereqs.container.then( function() {
8788 if ( prereqs === self._prereqs ) {
8789 containerPrereq();
8790 }
8791 });
8792
8793 $.when( prereqs.screen, prereqs.container ).done( function() {
8794 if ( prereqs === self._prereqs ) {
8795 self._prereqs = null;
8796 whenDone();
8797 }
8798 });
8799
8800 self._prereqs = prereqs;
8801 },
8802
8803 _animate: function( args ) {
8804 // NOTE before removing the default animation of the screen
8805 // this had an animate callback that would resolve the deferred
8806 // now the deferred is resolved immediately
8807 // TODO remove the dependency on the screen deferred
8808 this._ui.screen
8809 .removeClass( args.classToRemove )
8810 .addClass( args.screenClassToAdd );
8811
8812 args.prereqs.screen.resolve();
8813
8814 if ( args.transition && args.transition !== "none" ) {
8815 if ( args.applyTransition ) {
8816 this._applyTransition( args.transition );
8817 }
8818 if ( this._fallbackTransition ) {
8819 this._ui.container
8820 .animationComplete( $.proxy( args.prereqs.container, "resolve" ) )
8821 .addClass( args.containerClassToAdd )
8822 .removeClass( args.classToRemove );
8823 return;
8824 }
8825 }
8826 this._ui.container.removeClass( args.classToRemove );
8827 args.prereqs.container.resolve();
8828 },
8829
8830 // The desired coordinates passed in will be returned untouched if no reference element can be identified via
8831 // desiredPosition.positionTo. Nevertheless, this function ensures that its return value always contains valid
8832 // x and y coordinates by specifying the center middle of the window if the coordinates are absent.
8833 // options: { x: coordinate, y: coordinate, positionTo: string: "origin", "window", or jQuery selector
8834 _desiredCoords: function( o ) {
8835 var dst = null, offset, winCoords = windowCoords(), x = o.x, y = o.y, pTo = o.positionTo;
8836
8837 // Establish which element will serve as the reference
8838 if ( pTo && pTo !== "origin" ) {
8839 if ( pTo === "window" ) {
8840 x = winCoords.cx / 2 + winCoords.x;
8841 y = winCoords.cy / 2 + winCoords.y;
8842 } else {
8843 try {
8844 dst = $( pTo );
8845 } catch( e ) {
8846 dst = null;
8847 }
8848 if ( dst ) {
8849 dst.filter( ":visible" );
8850 if ( dst.length === 0 ) {
8851 dst = null;
8852 }
8853 }
8854 }
8855 }
8856
8857 // If an element was found, center over it
8858 if ( dst ) {
8859 offset = dst.offset();
8860 x = offset.left + dst.outerWidth() / 2;
8861 y = offset.top + dst.outerHeight() / 2;
8862 }
8863
8864 // Make sure x and y are valid numbers - center over the window
8865 if ( $.type( x ) !== "number" || isNaN( x ) ) {
8866 x = winCoords.cx / 2 + winCoords.x;
8867 }
8868 if ( $.type( y ) !== "number" || isNaN( y ) ) {
8869 y = winCoords.cy / 2 + winCoords.y;
8870 }
8871
8872 return { x: x, y: y };
8873 },
8874
8875 _reposition: function( o ) {
8876 // We only care about position-related parameters for repositioning
8877 o = { x: o.x, y: o.y, positionTo: o.positionTo };
8878 this._trigger( "beforeposition", undefined, o );
8879 this._ui.container.offset( this._placementCoords( this._desiredCoords( o ) ) );
8880 },
8881
8882 reposition: function( o ) {
8883 if ( this._isOpen ) {
8884 this._reposition( o );
8885 }
8886 },
8887
8888 _openPrereqsComplete: function() {
8889 this._ui.container.addClass( "ui-popup-active" );
8890 this._isOpen = true;
8891 this._resizeScreen();
8892 this._ui.container.attr( "tabindex", "0" ).focus();
8893 this._ignoreResizeEvents();
8894 this._trigger( "afteropen" );
8895 },
8896
8897 _open: function( options ) {
8898 var o = $.extend( {}, this.options, options ),
8899 // TODO move blacklist to private method
8900 androidBlacklist = ( function() {
8901 var w = window,
8902 ua = navigator.userAgent,
8903 // Rendering engine is Webkit, and capture major version
8904 wkmatch = ua.match( /AppleWebKit\/([0-9\.]+)/ ),
8905 wkversion = !!wkmatch && wkmatch[ 1 ],
8906 androidmatch = ua.match( /Android (\d+(?:\.\d+))/ ),
8907 andversion = !!androidmatch && androidmatch[ 1 ],
8908 chromematch = ua.indexOf( "Chrome" ) > -1;
8909
8910 // Platform is Android, WebKit version is greater than 534.13 ( Android 3.2.1 ) and not Chrome.
8911 if( androidmatch !== null && andversion === "4.0" && wkversion && wkversion > 534.13 && !chromematch ) {
8912 return true;
8913 }
8914 return false;
8915 }());
8916
8917 // Count down to triggering "popupafteropen" - we have two prerequisites:
8918 // 1. The popup window animation completes (container())
8919 // 2. The screen opacity animation completes (screen())
8920 this._createPrereqs(
8921 $.noop,
8922 $.noop,
8923 $.proxy( this, "_openPrereqsComplete" ) );
8924
8925 this._currentTransition = o.transition;
8926 this._applyTransition( o.transition );
8927
8928 if ( !this.options.theme ) {
8929 this._setTheme( this._page.jqmData( "theme" ) || $.mobile.getInheritedTheme( this._page, "c" ) );
8930 }
8931
8932 this._ui.screen.removeClass( "ui-screen-hidden" );
8933 this._ui.container.removeClass( "ui-popup-hidden" );
8934
8935 // Give applications a chance to modify the contents of the container before it appears
8936 this._reposition( o );
8937
8938 if ( this.options.overlayTheme && androidBlacklist ) {
8939 /* TODO:
8940 The native browser on Android 4.0.X ("Ice Cream Sandwich") suffers from an issue where the popup overlay appears to be z-indexed
8941 above the popup itself when certain other styles exist on the same page -- namely, any element set to `position: fixed` and certain
8942 types of input. These issues are reminiscent of previously uncovered bugs in older versions of Android's native browser:
8943 https://github.com/scottjehl/Device-Bugs/issues/3
8944
8945 This fix closes the following bugs ( I use "closes" with reluctance, and stress that this issue should be revisited as soon as possible ):
8946
8947 https://github.com/jquery/jquery-mobile/issues/4816
8948 https://github.com/jquery/jquery-mobile/issues/4844
8949 https://github.com/jquery/jquery-mobile/issues/4874
8950 */
8951
8952 // TODO sort out why this._page isn't working
8953 this.element.closest( ".ui-page" ).addClass( "ui-popup-open" );
8954 }
8955 this._animate({
8956 additionalCondition: true,
8957 transition: o.transition,
8958 classToRemove: "",
8959 screenClassToAdd: "in",
8960 containerClassToAdd: "in",
8961 applyTransition: false,
8962 prereqs: this._prereqs
8963 });
8964 },
8965
8966 _closePrereqScreen: function() {
8967 this._ui.screen
8968 .removeClass( "out" )
8969 .addClass( "ui-screen-hidden" );
8970 },
8971
8972 _closePrereqContainer: function() {
8973 this._ui.container
8974 .removeClass( "reverse out" )
8975 .addClass( "ui-popup-hidden" )
8976 .removeAttr( "style" );
8977 },
8978
8979 _closePrereqsDone: function() {
8980 var container = this._ui.container;
8981
8982 container.removeAttr( "tabindex" );
8983
8984 // remove the global mutex for popups
8985 $.mobile.popup.active = undefined;
8986
8987 // Blur elements inside the container, including the container
8988 $( ":focus", container[ 0 ] ).add( container[ 0 ] ).blur();
8989
8990 // alert users that the popup is closed
8991 this._trigger( "afterclose" );
8992 },
8993
8994 _close: function( immediate ) {
8995 this._ui.container.removeClass( "ui-popup-active" );
8996 this._page.removeClass( "ui-popup-open" );
8997
8998 this._isOpen = false;
8999
9000 // Count down to triggering "popupafterclose" - we have two prerequisites:
9001 // 1. The popup window reverse animation completes (container())
9002 // 2. The screen opacity animation completes (screen())
9003 this._createPrereqs(
9004 $.proxy( this, "_closePrereqScreen" ),
9005 $.proxy( this, "_closePrereqContainer" ),
9006 $.proxy( this, "_closePrereqsDone" ) );
9007
9008 this._animate( {
9009 additionalCondition: this._ui.screen.hasClass( "in" ),
9010 transition: ( immediate ? "none" : ( this._currentTransition ) ),
9011 classToRemove: "in",
9012 screenClassToAdd: "out",
9013 containerClassToAdd: "reverse out",
9014 applyTransition: true,
9015 prereqs: this._prereqs
9016 });
9017 },
9018
9019 _unenhance: function() {
9020 // Put the element back to where the placeholder was and remove the "ui-popup" class
9021 this._setTheme( "none" );
9022 this.element
9023 // Cannot directly insertAfter() - we need to detach() first, because
9024 // insertAfter() will do nothing if the payload div was not attached
9025 // to the DOM at the time the widget was created, and so the payload
9026 // will remain inside the container even after we call insertAfter().
9027 // If that happens and we remove the container a few lines below, we
9028 // will cause an infinite recursion - #5244
9029 .detach()
9030 .insertAfter( this._ui.placeholder )
9031 .removeClass( "ui-popup ui-overlay-shadow ui-corner-all" );
9032 this._ui.screen.remove();
9033 this._ui.container.remove();
9034 this._ui.placeholder.remove();
9035 },
9036
9037 _destroy: function() {
9038 if ( $.mobile.popup.active === this ) {
9039 this.element.one( "popupafterclose", $.proxy( this, "_unenhance" ) );
9040 this.close();
9041 } else {
9042 this._unenhance();
9043 }
9044 },
9045
9046 _closePopup: function( e, data ) {
9047 var parsedDst, toUrl, o = this.options, immediate = false;
9048
9049 // restore location on screen
9050 window.scrollTo( 0, this._scrollTop );
9051
9052 if ( e && e.type === "pagebeforechange" && data ) {
9053 // Determine whether we need to rapid-close the popup, or whether we can
9054 // take the time to run the closing transition
9055 if ( typeof data.toPage === "string" ) {
9056 parsedDst = data.toPage;
9057 } else {
9058 parsedDst = data.toPage.jqmData( "url" );
9059 }
9060 parsedDst = $.mobile.path.parseUrl( parsedDst );
9061 toUrl = parsedDst.pathname + parsedDst.search + parsedDst.hash;
9062
9063 if ( this._myUrl !== $.mobile.path.makeUrlAbsolute( toUrl ) ) {
9064 // Going to a different page - close immediately
9065 immediate = true;
9066 } else {
9067 e.preventDefault();
9068 }
9069 }
9070
9071 // remove nav bindings
9072 o.container.unbind( o.closeEvents );
9073 // unbind click handlers added when history is disabled
9074 this.element.undelegate( o.closeLinkSelector, o.closeLinkEvents );
9075
9076 this._close( immediate );
9077 },
9078
9079 // any navigation event after a popup is opened should close the popup
9080 // NOTE the pagebeforechange is bound to catch navigation events that don't
9081 // alter the url (eg, dialogs from popups)
9082 _bindContainerClose: function() {
9083 this.options.container
9084 .one( this.options.closeEvents, $.proxy( this, "_closePopup" ) );
9085 },
9086
9087 // TODO no clear deliniation of what should be here and
9088 // what should be in _open. Seems to be "visual" vs "history" for now
9089 open: function( options ) {
9090 var self = this, opts = this.options, url, hashkey, activePage, currentIsDialog, hasHash, urlHistory;
9091
9092 // make sure open is idempotent
9093 if( $.mobile.popup.active ) {
9094 return;
9095 }
9096
9097 // set the global popup mutex
9098 $.mobile.popup.active = this;
9099 this._scrollTop = $.mobile.window.scrollTop();
9100
9101 // if history alteration is disabled close on navigate events
9102 // and leave the url as is
9103 if( !( opts.history ) ) {
9104 self._open( options );
9105 self._bindContainerClose();
9106
9107 // When histoy is disabled we have to grab the data-rel
9108 // back link clicks so we can close the popup instead of
9109 // relying on history to do it for us
9110 self.element
9111 .delegate( opts.closeLinkSelector, opts.closeLinkEvents, function( e ) {
9112 self.close();
9113 e.preventDefault();
9114 });
9115
9116 return;
9117 }
9118
9119 // cache some values for min/readability
9120 urlHistory = $.mobile.urlHistory;
9121 hashkey = $.mobile.dialogHashKey;
9122 activePage = $.mobile.activePage;
9123 currentIsDialog = activePage.is( ".ui-dialog" );
9124 this._myUrl = url = urlHistory.getActive().url;
9125 hasHash = ( url.indexOf( hashkey ) > -1 ) && !currentIsDialog && ( urlHistory.activeIndex > 0 );
9126
9127 if ( hasHash ) {
9128 self._open( options );
9129 self._bindContainerClose();
9130 return;
9131 }
9132
9133 // if the current url has no dialog hash key proceed as normal
9134 // otherwise, if the page is a dialog simply tack on the hash key
9135 if ( url.indexOf( hashkey ) === -1 && !currentIsDialog ){
9136 url = url + (url.indexOf( "#" ) > -1 ? hashkey : "#" + hashkey);
9137 } else {
9138 url = $.mobile.path.parseLocation().hash + hashkey;
9139 }
9140
9141 // Tack on an extra hashkey if this is the first page and we've just reconstructed the initial hash
9142 if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
9143 url += hashkey;
9144 }
9145
9146 // swallow the the initial navigation event, and bind for the next
9147 $(window).one( "beforenavigate", function( e ) {
9148 e.preventDefault();
9149 self._open( options );
9150 self._bindContainerClose();
9151 });
9152
9153 this.urlAltered = true;
9154 $.mobile.navigate( url, {role: "dialog"} );
9155 },
9156
9157 close: function() {
9158 // make sure close is idempotent
9159 if( $.mobile.popup.active !== this ) {
9160 return;
9161 }
9162
9163 this._scrollTop = $.mobile.window.scrollTop();
9164
9165 if( this.options.history && this.urlAltered ) {
9166 $.mobile.back();
9167 this.urlAltered = false;
9168 } else {
9169 // simulate the nav bindings having fired
9170 this._closePopup();
9171 }
9172 }
9173});
9174
9175
9176// TODO this can be moved inside the widget
9177$.mobile.popup.handleLink = function( $link ) {
9178 var closestPage = $link.closest( ":jqmData(role='page')" ),
9179 scope = ( ( closestPage.length === 0 ) ? $( "body" ) : closestPage ),
9180 // NOTE make sure to get only the hash, ie7 (wp7) return the absolute href
9181 // in this case ruining the element selection
9182 popup = $( $.mobile.path.parseUrl($link.attr( "href" )).hash, scope[0] ),
9183 offset;
9184
9185 if ( popup.data( "mobile-popup" ) ) {
9186 offset = $link.offset();
9187 popup.popup( "open", {
9188 x: offset.left + $link.outerWidth() / 2,
9189 y: offset.top + $link.outerHeight() / 2,
9190 transition: $link.jqmData( "transition" ),
9191 positionTo: $link.jqmData( "position-to" )
9192 });
9193 }
9194
9195 //remove after delay
9196 setTimeout( function() {
9197 // Check if we are in a listview
9198 var $parent = $link.parent().parent();
9199 if ($parent.hasClass("ui-li")) {
9200 $link = $parent.parent();
9201 }
9202 $link.removeClass( $.mobile.activeBtnClass );
9203 }, 300 );
9204};
9205
9206// TODO move inside _create
9207$.mobile.document.bind( "pagebeforechange", function( e, data ) {
9208 if ( data.options.role === "popup" ) {
9209 $.mobile.popup.handleLink( data.options.link );
9210 e.preventDefault();
9211 }
9212});
9213
9214$.mobile.document.bind( "pagecreate create", function( e ) {
9215 $.mobile.popup.prototype.enhanceWithin( e.target, true );
9216});
9217
9218})( jQuery );
9219
9220/*
9221* custom "selectmenu" plugin
9222*/
9223
9224(function( $, undefined ) {
9225 var extendSelect = function( widget ) {
9226
9227 var select = widget.select,
9228 origDestroy = widget._destroy,
9229 selectID = widget.selectID,
9230 prefix = ( selectID ? selectID : ( ( $.mobile.ns || "" ) + "uuid-" + widget.uuid ) ),
9231 popupID = prefix + "-listbox",
9232 dialogID = prefix + "-dialog",
9233 label = widget.label,
9234 thisPage = widget.select.closest( ".ui-page" ),
9235 selectOptions = widget._selectOptions(),
9236 isMultiple = widget.isMultiple = widget.select[ 0 ].multiple,
9237 buttonId = selectID + "-button",
9238 menuId = selectID + "-menu",
9239 menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' id='" + dialogID + "' data-" +$.mobile.ns + "theme='"+ widget.options.theme +"' data-" +$.mobile.ns + "overlay-theme='"+ widget.options.overlayTheme +"'>" +
9240 "<div data-" + $.mobile.ns + "role='header'>" +
9241 "<div class='ui-title'>" + label.getEncodedText() + "</div>"+
9242 "</div>"+
9243 "<div data-" + $.mobile.ns + "role='content'></div>"+
9244 "</div>" ),
9245
9246 listbox = $( "<div id='" + popupID + "' class='ui-selectmenu'>" ).insertAfter( widget.select ).popup( { theme: widget.options.overlayTheme } ),
9247
9248 list = $( "<ul>", {
9249 "class": "ui-selectmenu-list",
9250 "id": menuId,
9251 "role": "listbox",
9252 "aria-labelledby": buttonId
9253 }).attr( "data-" + $.mobile.ns + "theme", widget.options.theme )
9254 .attr( "data-" + $.mobile.ns + "divider-theme", widget.options.dividerTheme )
9255 .appendTo( listbox ),
9256
9257
9258 header = $( "<div>", {
9259 "class": "ui-header ui-bar-" + widget.options.theme
9260 }).prependTo( listbox ),
9261
9262 headerTitle = $( "<h1>", {
9263 "class": "ui-title"
9264 }).appendTo( header ),
9265
9266 menuPageContent,
9267 menuPageClose,
9268 headerClose;
9269
9270 if ( widget.isMultiple ) {
9271 headerClose = $( "<a>", {
9272 "text": widget.options.closeText,
9273 "href": "#",
9274 "class": "ui-btn-left"
9275 }).attr( "data-" + $.mobile.ns + "iconpos", "notext" ).attr( "data-" + $.mobile.ns + "icon", "delete" ).appendTo( header ).buttonMarkup();
9276 }
9277
9278 $.extend( widget, {
9279 select: widget.select,
9280 selectID: selectID,
9281 buttonId: buttonId,
9282 menuId: menuId,
9283 popupID: popupID,
9284 dialogID: dialogID,
9285 thisPage: thisPage,
9286 menuPage: menuPage,
9287 label: label,
9288 selectOptions: selectOptions,
9289 isMultiple: isMultiple,
9290 theme: widget.options.theme,
9291 listbox: listbox,
9292 list: list,
9293 header: header,
9294 headerTitle: headerTitle,
9295 headerClose: headerClose,
9296 menuPageContent: menuPageContent,
9297 menuPageClose: menuPageClose,
9298 placeholder: "",
9299
9300 build: function() {
9301 var self = this,
9302 escapeId = function( id ) {
9303 return id.replace( /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g, "\\$1" );
9304 };
9305
9306 // Create list from select, update state
9307 self.refresh();
9308
9309 if ( self._origTabIndex === undefined ) {
9310 // Map undefined to false, because self._origTabIndex === undefined
9311 // indicates that we have not yet checked whether the select has
9312 // originally had a tabindex attribute, whereas false indicates that
9313 // we have checked the select for such an attribute, and have found
9314 // none present.
9315 self._origTabIndex = ( self.select[ 0 ].getAttribute( "tabindex" ) === null ) ? false : self.select.attr( "tabindex" );
9316 }
9317 self.select.attr( "tabindex", "-1" ).focus(function() {
9318 $( this ).blur();
9319 self.button.focus();
9320 });
9321
9322 // Button events
9323 self.button.bind( "vclick keydown" , function( event ) {
9324 if ( self.options.disabled || self.isOpen ) {
9325 return;
9326 }
9327
9328 if (event.type === "vclick" ||
9329 event.keyCode && (event.keyCode === $.mobile.keyCode.ENTER ||
9330 event.keyCode === $.mobile.keyCode.SPACE)) {
9331
9332 self._decideFormat();
9333 if ( self.menuType === "overlay" ) {
9334 self.button.attr( "href", "#" + escapeId( self.popupID ) ).attr( "data-" + ( $.mobile.ns || "" ) + "rel", "popup" );
9335 } else {
9336 self.button.attr( "href", "#" + escapeId( self.dialogID ) ).attr( "data-" + ( $.mobile.ns || "" ) + "rel", "dialog" );
9337 }
9338 self.isOpen = true;
9339 // Do not prevent default, so the navigation may have a chance to actually open the chosen format
9340 }
9341 });
9342
9343 // Events for list items
9344 self.list.attr( "role", "listbox" )
9345 .bind( "focusin", function( e ) {
9346 $( e.target )
9347 .attr( "tabindex", "0" )
9348 .trigger( "vmouseover" );
9349
9350 })
9351 .bind( "focusout", function( e ) {
9352 $( e.target )
9353 .attr( "tabindex", "-1" )
9354 .trigger( "vmouseout" );
9355 })
9356 .delegate( "li:not(.ui-disabled, .ui-li-divider)", "click", function( event ) {
9357
9358 // index of option tag to be selected
9359 var oldIndex = self.select[ 0 ].selectedIndex,
9360 newIndex = self.list.find( "li:not(.ui-li-divider)" ).index( this ),
9361 option = self._selectOptions().eq( newIndex )[ 0 ];
9362
9363 // toggle selected status on the tag for multi selects
9364 option.selected = self.isMultiple ? !option.selected : true;
9365
9366 // toggle checkbox class for multiple selects
9367 if ( self.isMultiple ) {
9368 $( this ).find( ".ui-icon" )
9369 .toggleClass( "ui-icon-checkbox-on", option.selected )
9370 .toggleClass( "ui-icon-checkbox-off", !option.selected );
9371 }
9372
9373 // trigger change if value changed
9374 if ( self.isMultiple || oldIndex !== newIndex ) {
9375 self.select.trigger( "change" );
9376 }
9377
9378 // hide custom select for single selects only - otherwise focus clicked item
9379 // We need to grab the clicked item the hard way, because the list may have been rebuilt
9380 if ( self.isMultiple ) {
9381 self.list.find( "li:not(.ui-li-divider)" ).eq( newIndex )
9382 .addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
9383 }
9384 else {
9385 self.close();
9386 }
9387
9388 event.preventDefault();
9389 })
9390 .keydown(function( event ) { //keyboard events for menu items
9391 var target = $( event.target ),
9392 li = target.closest( "li" ),
9393 prev, next;
9394
9395 // switch logic based on which key was pressed
9396 switch ( event.keyCode ) {
9397 // up or left arrow keys
9398 case 38:
9399 prev = li.prev().not( ".ui-selectmenu-placeholder" );
9400
9401 if ( prev.is( ".ui-li-divider" ) ) {
9402 prev = prev.prev();
9403 }
9404
9405 // if there's a previous option, focus it
9406 if ( prev.length ) {
9407 target
9408 .blur()
9409 .attr( "tabindex", "-1" );
9410
9411 prev.addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
9412 }
9413
9414 return false;
9415 // down or right arrow keys
9416 case 40:
9417 next = li.next();
9418
9419 if ( next.is( ".ui-li-divider" ) ) {
9420 next = next.next();
9421 }
9422
9423 // if there's a next option, focus it
9424 if ( next.length ) {
9425 target
9426 .blur()
9427 .attr( "tabindex", "-1" );
9428
9429 next.addClass( "ui-btn-down-" + widget.options.theme ).find( "a" ).first().focus();
9430 }
9431
9432 return false;
9433 // If enter or space is pressed, trigger click
9434 case 13:
9435 case 32:
9436 target.trigger( "click" );
9437
9438 return false;
9439 }
9440 });
9441
9442 // button refocus ensures proper height calculation
9443 // by removing the inline style and ensuring page inclusion
9444 self.menuPage.bind( "pagehide", function() {
9445 // TODO centralize page removal binding / handling in the page plugin.
9446 // Suggestion from @jblas to do refcounting
9447 //
9448 // TODO extremely confusing dependency on the open method where the pagehide.remove
9449 // bindings are stripped to prevent the parent page from disappearing. The way
9450 // we're keeping pages in the DOM right now sucks
9451 //
9452 // rebind the page remove that was unbound in the open function
9453 // to allow for the parent page removal from actions other than the use
9454 // of a dialog sized custom select
9455 //
9456 // doing this here provides for the back button on the custom select dialog
9457 $.mobile._bindPageRemove.call( self.thisPage );
9458 });
9459
9460 // Events on the popup
9461 self.listbox.bind( "popupafterclose", function( event ) {
9462 self.close();
9463 });
9464
9465 // Close button on small overlays
9466 if ( self.isMultiple ) {
9467 self.headerClose.click(function() {
9468 if ( self.menuType === "overlay" ) {
9469 self.close();
9470 return false;
9471 }
9472 });
9473 }
9474
9475 // track this dependency so that when the parent page
9476 // is removed on pagehide it will also remove the menupage
9477 self.thisPage.addDependents( this.menuPage );
9478 },
9479
9480 _isRebuildRequired: function() {
9481 var list = this.list.find( "li" ),
9482 options = this._selectOptions();
9483
9484 // TODO exceedingly naive method to determine difference
9485 // ignores value changes etc in favor of a forcedRebuild
9486 // from the user in the refresh method
9487 return options.text() !== list.text();
9488 },
9489
9490 selected: function() {
9491 return this._selectOptions().filter( ":selected:not( :jqmData(placeholder='true') )" );
9492 },
9493
9494 refresh: function( forceRebuild , foo ) {
9495 var self = this,
9496 select = this.element,
9497 isMultiple = this.isMultiple,
9498 indicies;
9499
9500 if ( forceRebuild || this._isRebuildRequired() ) {
9501 self._buildList();
9502 }
9503
9504 indicies = this.selectedIndices();
9505
9506 self.setButtonText();
9507 self.setButtonCount();
9508
9509 self.list.find( "li:not(.ui-li-divider)" )
9510 .removeClass( $.mobile.activeBtnClass )
9511 .attr( "aria-selected", false )
9512 .each(function( i ) {
9513
9514 if ( $.inArray( i, indicies ) > -1 ) {
9515 var item = $( this );
9516
9517 // Aria selected attr
9518 item.attr( "aria-selected", true );
9519
9520 // Multiple selects: add the "on" checkbox state to the icon
9521 if ( self.isMultiple ) {
9522 item.find( ".ui-icon" ).removeClass( "ui-icon-checkbox-off" ).addClass( "ui-icon-checkbox-on" );
9523 } else {
9524 if ( item.is( ".ui-selectmenu-placeholder" ) ) {
9525 item.next().addClass( $.mobile.activeBtnClass );
9526 } else {
9527 item.addClass( $.mobile.activeBtnClass );
9528 }
9529 }
9530 }
9531 });
9532 },
9533
9534 close: function() {
9535 if ( this.options.disabled || !this.isOpen ) {
9536 return;
9537 }
9538
9539 var self = this;
9540
9541 if ( self.menuType === "page" ) {
9542 self.menuPage.dialog( "close" );
9543 self.list.appendTo( self.listbox );
9544 } else {
9545 self.listbox.popup( "close" );
9546 }
9547
9548 self._focusButton();
9549 // allow the dialog to be closed again
9550 self.isOpen = false;
9551 },
9552
9553 open: function() {
9554 this.button.click();
9555 },
9556
9557 _decideFormat: function() {
9558 var self = this,
9559 $window = $.mobile.window,
9560 selfListParent = self.list.parent(),
9561 menuHeight = selfListParent.outerHeight(),
9562 menuWidth = selfListParent.outerWidth(),
9563 activePage = $( "." + $.mobile.activePageClass ),
9564 scrollTop = $window.scrollTop(),
9565 btnOffset = self.button.offset().top,
9566 screenHeight = $window.height(),
9567 screenWidth = $window.width();
9568
9569 function focusMenuItem() {
9570 var selector = self.list.find( "." + $.mobile.activeBtnClass + " a" );
9571 if ( selector.length === 0 ) {
9572 selector = self.list.find( "li.ui-btn:not( :jqmData(placeholder='true') ) a" );
9573 }
9574 selector.first().focus().closest( "li" ).addClass( "ui-btn-down-" + widget.options.theme );
9575 }
9576
9577 if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
9578
9579 self.menuPage.appendTo( $.mobile.pageContainer ).page();
9580 self.menuPageContent = menuPage.find( ".ui-content" );
9581 self.menuPageClose = menuPage.find( ".ui-header a" );
9582
9583 // prevent the parent page from being removed from the DOM,
9584 // otherwise the results of selecting a list item in the dialog
9585 // fall into a black hole
9586 self.thisPage.unbind( "pagehide.remove" );
9587
9588 //for WebOS/Opera Mini (set lastscroll using button offset)
9589 if ( scrollTop === 0 && btnOffset > screenHeight ) {
9590 self.thisPage.one( "pagehide", function() {
9591 $( this ).jqmData( "lastScroll", btnOffset );
9592 });
9593 }
9594
9595 self.menuPage
9596 .one( "pageshow", function() {
9597 focusMenuItem();
9598 })
9599 .one( "pagehide", function() {
9600 self.close();
9601 });
9602
9603 self.menuType = "page";
9604 self.menuPageContent.append( self.list );
9605 self.menuPage.find("div .ui-title").text(self.label.text());
9606 } else {
9607 self.menuType = "overlay";
9608
9609 self.listbox.one( "popupafteropen", focusMenuItem );
9610 }
9611 },
9612
9613 _buildList: function() {
9614 var self = this,
9615 o = this.options,
9616 placeholder = this.placeholder,
9617 needPlaceholder = true,
9618 optgroups = [],
9619 lis = [],
9620 dataIcon = self.isMultiple ? "checkbox-off" : "false";
9621
9622 self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
9623
9624 var $options = self.select.find( "option" ),
9625 numOptions = $options.length,
9626 select = this.select[ 0 ],
9627 dataPrefix = 'data-' + $.mobile.ns,
9628 dataIndexAttr = dataPrefix + 'option-index',
9629 dataIconAttr = dataPrefix + 'icon',
9630 dataRoleAttr = dataPrefix + 'role',
9631 dataPlaceholderAttr = dataPrefix + 'placeholder',
9632 fragment = document.createDocumentFragment(),
9633 isPlaceholderItem = false,
9634 optGroup;
9635
9636 for (var i = 0; i < numOptions;i++, isPlaceholderItem = false) {
9637 var option = $options[i],
9638 $option = $( option ),
9639 parent = option.parentNode,
9640 text = $option.text(),
9641 anchor = document.createElement( 'a' ),
9642 classes = [];
9643
9644 anchor.setAttribute( 'href', '#' );
9645 anchor.appendChild( document.createTextNode( text ) );
9646
9647 // Are we inside an optgroup?
9648 if ( parent !== select && parent.nodeName.toLowerCase() === "optgroup" ) {
9649 var optLabel = parent.getAttribute( 'label' );
9650 if ( optLabel !== optGroup ) {
9651 var divider = document.createElement( 'li' );
9652 divider.setAttribute( dataRoleAttr, 'list-divider' );
9653 divider.setAttribute( 'role', 'option' );
9654 divider.setAttribute( 'tabindex', '-1' );
9655 divider.appendChild( document.createTextNode( optLabel ) );
9656 fragment.appendChild( divider );
9657 optGroup = optLabel;
9658 }
9659 }
9660
9661 if ( needPlaceholder && ( !option.getAttribute( "value" ) || text.length === 0 || $option.jqmData( "placeholder" ) ) ) {
9662 needPlaceholder = false;
9663 isPlaceholderItem = true;
9664
9665 // If we have identified a placeholder, record the fact that it was
9666 // us who have added the placeholder to the option and mark it
9667 // retroactively in the select as well
9668 if ( null === option.getAttribute( dataPlaceholderAttr ) ) {
9669 this._removePlaceholderAttr = true;
9670 }
9671 option.setAttribute( dataPlaceholderAttr, true );
9672 if ( o.hidePlaceholderMenuItems ) {
9673 classes.push( "ui-selectmenu-placeholder" );
9674 }
9675 if ( placeholder !== text ) {
9676 placeholder = self.placeholder = text;
9677 }
9678 }
9679
9680 var item = document.createElement('li');
9681 if ( option.disabled ) {
9682 classes.push( "ui-disabled" );
9683 item.setAttribute('aria-disabled',true);
9684 }
9685 item.setAttribute( dataIndexAttr,i );
9686 item.setAttribute( dataIconAttr, dataIcon );
9687 if ( isPlaceholderItem ) {
9688 item.setAttribute( dataPlaceholderAttr, true );
9689 }
9690 item.className = classes.join( " " );
9691 item.setAttribute( 'role', 'option' );
9692 anchor.setAttribute( 'tabindex', '-1' );
9693 item.appendChild( anchor );
9694 fragment.appendChild( item );
9695 }
9696
9697 self.list[0].appendChild( fragment );
9698
9699 // Hide header if it's not a multiselect and there's no placeholder
9700 if ( !this.isMultiple && !placeholder.length ) {
9701 this.header.hide();
9702 } else {
9703 this.headerTitle.text( this.placeholder );
9704 }
9705
9706 // Now populated, create listview
9707 self.list.listview();
9708 },
9709
9710 _button: function() {
9711 return $( "<a>", {
9712 "href": "#",
9713 "role": "button",
9714 // TODO value is undefined at creation
9715 "id": this.buttonId,
9716 "aria-haspopup": "true",
9717
9718 // TODO value is undefined at creation
9719 "aria-owns": this.menuId
9720 });
9721 },
9722
9723 _destroy: function() {
9724 this.close();
9725
9726 // Restore the tabindex attribute to its original value
9727 if ( this._origTabIndex !== undefined ) {
9728 if ( this._origTabIndex !== false ) {
9729 this.select.attr( "tabindex", this._origTabIndex );
9730 } else {
9731 this.select.removeAttr( "tabindex" );
9732 }
9733 }
9734
9735 // Remove the placeholder attribute if we were the ones to add it
9736 if ( this._removePlaceholderAttr ) {
9737 this._selectOptions().removeAttr( "data-" + $.mobile.ns + "placeholder" );
9738 }
9739
9740 // Remove the popup
9741 this.listbox.remove();
9742
9743 // Remove the dialog
9744 this.menuPage.remove();
9745
9746 // Chain up
9747 origDestroy.apply( this, arguments );
9748 }
9749 });
9750 };
9751
9752 // issue #3894 - core doesn't trigger events on disabled delegates
9753 $.mobile.document.bind( "selectmenubeforecreate", function( event ) {
9754 var selectmenuWidget = $( event.target ).data( "mobile-selectmenu" );
9755
9756 if ( !selectmenuWidget.options.nativeMenu &&
9757 selectmenuWidget.element.parents( ":jqmData(role='popup')" ).length === 0 ) {
9758 extendSelect( selectmenuWidget );
9759 }
9760 });
9761})( jQuery );
9762
9763(function( $, undefined ) {
9764
9765 $.widget( "mobile.controlgroup", $.mobile.widget, $.extend( {
9766 options: {
9767 shadow: false,
9768 corners: true,
9769 excludeInvisible: true,
9770 type: "vertical",
9771 mini: false,
9772 initSelector: ":jqmData(role='controlgroup')"
9773 },
9774
9775 _create: function() {
9776 var $el = this.element,
9777 ui = {
9778 inner: $( "<div class='ui-controlgroup-controls'></div>" ),
9779 legend: $( "<div role='heading' class='ui-controlgroup-label'></div>" )
9780 },
9781 grouplegend = $el.children( "legend" ),
9782 self = this;
9783
9784 // Apply the proto
9785 $el.wrapInner( ui.inner );
9786 if ( grouplegend.length ) {
9787 ui.legend.append( grouplegend ).insertBefore( $el.children( 0 ) );
9788 }
9789 $el.addClass( "ui-corner-all ui-controlgroup" );
9790
9791 $.extend( this, {
9792 _initialRefresh: true
9793 });
9794
9795 $.each( this.options, function( key, value ) {
9796 // Cause initial options to be applied by their handler by temporarily setting the option to undefined
9797 // - the handler then sets it to the initial value
9798 self.options[ key ] = undefined;
9799 self._setOption( key, value, true );
9800 });
9801 },
9802
9803 _init: function() {
9804 this.refresh();
9805 },
9806
9807 _setOption: function( key, value ) {
9808 var setter = "_set" + key.charAt( 0 ).toUpperCase() + key.slice( 1 );
9809
9810 if ( this[ setter ] !== undefined ) {
9811 this[ setter ]( value );
9812 }
9813
9814 this._super( key, value );
9815 this.element.attr( "data-" + ( $.mobile.ns || "" ) + ( key.replace( /([A-Z])/, "-$1" ).toLowerCase() ), value );
9816 },
9817
9818 _setType: function( value ) {
9819 this.element
9820 .removeClass( "ui-controlgroup-horizontal ui-controlgroup-vertical" )
9821 .addClass( "ui-controlgroup-" + value );
9822 this.refresh();
9823 },
9824
9825 _setCorners: function( value ) {
9826 this.element.toggleClass( "ui-corner-all", value );
9827 },
9828
9829 _setShadow: function( value ) {
9830 this.element.toggleClass( "ui-shadow", value );
9831 },
9832
9833 _setMini: function( value ) {
9834 this.element.toggleClass( "ui-mini", value );
9835 },
9836
9837 container: function() {
9838 return this.element.children( ".ui-controlgroup-controls" );
9839 },
9840
9841 refresh: function() {
9842 var els = this.element.find( ".ui-btn" ).not( ".ui-slider-handle" ),
9843 create = this._initialRefresh;
9844 if ( $.mobile.checkboxradio ) {
9845 this.element.find( ":mobile-checkboxradio" ).checkboxradio( "refresh" );
9846 }
9847 this._addFirstLastClasses( els, this.options.excludeInvisible ? this._getVisibles( els, create ) : els, create );
9848 this._initialRefresh = false;
9849 }
9850 }, $.mobile.behaviors.addFirstLastClasses ) );
9851
9852 // TODO: Implement a mechanism to allow widgets to become enhanced in the
9853 // correct order when their correct enhancement depends on other widgets in
9854 // the page being correctly enhanced already.
9855 //
9856 // For now, we wait until dom-ready to attach the controlgroup's enhancement
9857 // hook, because by that time, all the other widgets' enhancement hooks should
9858 // already be in place, ensuring that all widgets that need to be grouped will
9859 // already have been enhanced by the time the controlgroup is created.
9860 $( function() {
9861 $.mobile.document.bind( "pagecreate create", function( e ) {
9862 $.mobile.controlgroup.prototype.enhanceWithin( e.target, true );
9863 });
9864 });
9865})(jQuery);
9866
9867(function( $, undefined ) {
9868
9869$( document ).bind( "pagecreate create", function( e ) {
9870
9871 //links within content areas, tests included with page
9872 $( e.target )
9873 .find( "a" )
9874 .jqmEnhanceable()
9875 .filter( ":jqmData(rel='popup')[href][href!='']" )
9876 .each( function() {
9877 // Accessibility info for popups
9878 var e = this,
9879 href = $( this ).attr( "href" ),
9880 idref = href.substring( 1 );
9881
9882 e.setAttribute( "aria-haspopup", true );
9883 e.setAttribute( "aria-owns", idref );
9884 e.setAttribute( "aria-expanded", false );
9885 $( document )
9886 .on( "popupafteropen", href, function() {
9887 e.setAttribute( "aria-expanded", true );
9888 })
9889 .on( "popupafterclose", href, function() {
9890 e.setAttribute( "aria-expanded", false );
9891 });
9892 })
9893 .end()
9894 .not( ".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')" )
9895 .addClass( "ui-link" );
9896
9897});
9898
9899})( jQuery );
9900
9901
9902(function( $, undefined ) {
9903
9904
9905 $.widget( "mobile.fixedtoolbar", $.mobile.widget, {
9906 options: {
9907 visibleOnPageShow: true,
9908 disablePageZoom: true,
9909 transition: "slide", //can be none, fade, slide (slide maps to slideup or slidedown)
9910 fullscreen: false,
9911 tapToggle: true,
9912 tapToggleBlacklist: "a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed, .ui-popup, .ui-panel, .ui-panel-dismiss-open",
9913 hideDuringFocus: "input, textarea, select",
9914 updatePagePadding: true,
9915 trackPersistentToolbars: true,
9916
9917 // Browser detection! Weeee, here we go...
9918 // Unfortunately, position:fixed is costly, not to mention probably impossible, to feature-detect accurately.
9919 // Some tests exist, but they currently return false results in critical devices and browsers, which could lead to a broken experience.
9920 // Testing fixed positioning is also pretty obtrusive to page load, requiring injected elements and scrolling the window
9921 // The following function serves to rule out some popular browsers with known fixed-positioning issues
9922 // This is a plugin option like any other, so feel free to improve or overwrite it
9923 supportBlacklist: function() {
9924 return !$.support.fixedPosition;
9925 },
9926 initSelector: ":jqmData(position='fixed')"
9927 },
9928
9929 _create: function() {
9930
9931 var self = this,
9932 o = self.options,
9933 $el = self.element,
9934 tbtype = $el.is( ":jqmData(role='header')" ) ? "header" : "footer",
9935 $page = $el.closest( ".ui-page" );
9936
9937 // Feature detecting support for
9938 if ( o.supportBlacklist() ) {
9939 self.destroy();
9940 return;
9941 }
9942
9943 $el.addClass( "ui-"+ tbtype +"-fixed" );
9944
9945 // "fullscreen" overlay positioning
9946 if ( o.fullscreen ) {
9947 $el.addClass( "ui-"+ tbtype +"-fullscreen" );
9948 $page.addClass( "ui-page-" + tbtype + "-fullscreen" );
9949 }
9950 // If not fullscreen, add class to page to set top or bottom padding
9951 else{
9952 $page.addClass( "ui-page-" + tbtype + "-fixed" );
9953 }
9954
9955 $.extend( this, {
9956 _thisPage: null
9957 });
9958
9959 self._addTransitionClass();
9960 self._bindPageEvents();
9961 self._bindToggleHandlers();
9962 },
9963
9964 _addTransitionClass: function() {
9965 var tclass = this.options.transition;
9966
9967 if ( tclass && tclass !== "none" ) {
9968 // use appropriate slide for header or footer
9969 if ( tclass === "slide" ) {
9970 tclass = this.element.is( ".ui-header" ) ? "slidedown" : "slideup";
9971 }
9972
9973 this.element.addClass( tclass );
9974 }
9975 },
9976
9977 _bindPageEvents: function() {
9978 this._thisPage = this.element.closest( ".ui-page" );
9979 //page event bindings
9980 // Fixed toolbars require page zoom to be disabled, otherwise usability issues crop up
9981 // This method is meant to disable zoom while a fixed-positioned toolbar page is visible
9982 this._on( this._thisPage, {
9983 "pagebeforeshow": "_handlePageBeforeShow",
9984 "webkitAnimationStart":"_handleAnimationStart",
9985 "animationstart":"_handleAnimationStart",
9986 "updatelayout": "_handleAnimationStart",
9987 "pageshow": "_handlePageShow",
9988 "pagebeforehide": "_handlePageBeforeHide"
9989 });
9990 },
9991
9992 _handlePageBeforeShow: function() {
9993 var o = this.options;
9994 if ( o.disablePageZoom ) {
9995 $.mobile.zoom.disable( true );
9996 }
9997 if ( !o.visibleOnPageShow ) {
9998 this.hide( true );
9999 }
10000 },
10001
10002 _handleAnimationStart: function() {
10003 if ( this.options.updatePagePadding ) {
10004 this.updatePagePadding( this._thisPage );
10005 }
10006 },
10007
10008 _handlePageShow: function() {
10009 this.updatePagePadding( this._thisPage );
10010 if ( this.options.updatePagePadding ) {
10011 this._on( $.mobile.window, { "throttledresize": "updatePagePadding" } );
10012 }
10013 },
10014
10015 _handlePageBeforeHide: function( e, ui ) {
10016 var o = this.options;
10017
10018 if ( o.disablePageZoom ) {
10019 $.mobile.zoom.enable( true );
10020 }
10021 if ( o.updatePagePadding ) {
10022 this._off( $.mobile.window, "throttledresize" );
10023 }
10024
10025 if ( o.trackPersistentToolbars ) {
10026 var thisFooter = $( ".ui-footer-fixed:jqmData(id)", this._thisPage ),
10027 thisHeader = $( ".ui-header-fixed:jqmData(id)", this._thisPage ),
10028 nextFooter = thisFooter.length && ui.nextPage && $( ".ui-footer-fixed:jqmData(id='" + thisFooter.jqmData( "id" ) + "')", ui.nextPage ) || $(),
10029 nextHeader = thisHeader.length && ui.nextPage && $( ".ui-header-fixed:jqmData(id='" + thisHeader.jqmData( "id" ) + "')", ui.nextPage ) || $();
10030
10031 if ( nextFooter.length || nextHeader.length ) {
10032
10033 nextFooter.add( nextHeader ).appendTo( $.mobile.pageContainer );
10034
10035 ui.nextPage.one( "pageshow", function() {
10036 nextHeader.prependTo( this );
10037 nextFooter.appendTo( this );
10038 });
10039 }
10040 }
10041 },
10042
10043 _visible: true,
10044
10045 // This will set the content element's top or bottom padding equal to the toolbar's height
10046 updatePagePadding: function( tbPage ) {
10047 var $el = this.element,
10048 header = $el.is( ".ui-header" ),
10049 pos = parseFloat( $el.css( header ? "top" : "bottom" ) );
10050
10051 // This behavior only applies to "fixed", not "fullscreen"
10052 if ( this.options.fullscreen ) { return; }
10053
10054 // tbPage argument can be a Page object or an event, if coming from throttled resize.
10055 tbPage = ( tbPage && tbPage.type === undefined && tbPage ) || this._thisPage || $el.closest( ".ui-page" );
10056 $( tbPage ).css( "padding-" + ( header ? "top" : "bottom" ), $el.outerHeight() + pos );
10057 },
10058
10059 _useTransition: function( notransition ) {
10060 var $win = $.mobile.window,
10061 $el = this.element,
10062 scroll = $win.scrollTop(),
10063 elHeight = $el.height(),
10064 pHeight = $el.closest( ".ui-page" ).height(),
10065 viewportHeight = $.mobile.getScreenHeight(),
10066 tbtype = $el.is( ":jqmData(role='header')" ) ? "header" : "footer";
10067
10068 return !notransition &&
10069 ( this.options.transition && this.options.transition !== "none" &&
10070 (
10071 ( tbtype === "header" && !this.options.fullscreen && scroll > elHeight ) ||
10072 ( tbtype === "footer" && !this.options.fullscreen && scroll + viewportHeight < pHeight - elHeight )
10073 ) || this.options.fullscreen
10074 );
10075 },
10076
10077 show: function( notransition ) {
10078 var hideClass = "ui-fixed-hidden",
10079 $el = this.element;
10080
10081 if ( this._useTransition( notransition ) ) {
10082 $el
10083 .removeClass( "out " + hideClass )
10084 .addClass( "in" )
10085 .animationComplete(function () {
10086 $el.removeClass('in');
10087 });
10088 }
10089 else {
10090 $el.removeClass( hideClass );
10091 }
10092 this._visible = true;
10093 },
10094
10095 hide: function( notransition ) {
10096 var hideClass = "ui-fixed-hidden",
10097 $el = this.element,
10098 // if it's a slide transition, our new transitions need the reverse class as well to slide outward
10099 outclass = "out" + ( this.options.transition === "slide" ? " reverse" : "" );
10100
10101 if( this._useTransition( notransition ) ) {
10102 $el
10103 .addClass( outclass )
10104 .removeClass( "in" )
10105 .animationComplete(function() {
10106 $el.addClass( hideClass ).removeClass( outclass );
10107 });
10108 }
10109 else {
10110 $el.addClass( hideClass ).removeClass( outclass );
10111 }
10112 this._visible = false;
10113 },
10114
10115 toggle: function() {
10116 this[ this._visible ? "hide" : "show" ]();
10117 },
10118
10119 _bindToggleHandlers: function() {
10120 var self = this,
10121 o = self.options,
10122 $el = self.element,
10123 delayShow, delayHide,
10124 isVisible = true;
10125
10126 // tap toggle
10127 $el.closest( ".ui-page" )
10128 .bind( "vclick", function( e ) {
10129 if ( o.tapToggle && !$( e.target ).closest( o.tapToggleBlacklist ).length ) {
10130 self.toggle();
10131 }
10132 })
10133 .bind( "focusin focusout", function( e ) {
10134 //this hides the toolbars on a keyboard pop to give more screen room and prevent ios bug which
10135 //positions fixed toolbars in the middle of the screen on pop if the input is near the top or
10136 //bottom of the screen addresses issues #4410 Footer navbar moves up when clicking on a textbox in an Android environment
10137 //and issue #4113 Header and footer change their position after keyboard popup - iOS
10138 //and issue #4410 Footer navbar moves up when clicking on a textbox in an Android environment
10139 if ( screen.width < 1025 && $( e.target ).is( o.hideDuringFocus ) && !$( e.target ).closest( ".ui-header-fixed, .ui-footer-fixed" ).length ) {
10140 //Fix for issue #4724 Moving through form in Mobile Safari with "Next" and "Previous" system
10141 //controls causes fixed position, tap-toggle false Header to reveal itself
10142 // isVisible instead of self._visible because the focusin and focusout events fire twice at the same time
10143 // Also use a delay for hiding the toolbars because on Android native browser focusin is direclty followed
10144 // by a focusout when a native selects opens and the other way around when it closes.
10145 if ( e.type === "focusout" && !isVisible ) {
10146 isVisible = true;
10147 //wait for the stack to unwind and see if we have jumped to another input
10148 clearTimeout( delayHide );
10149 delayShow = setTimeout( function() {
10150 self.show();
10151 }, 0 );
10152 } else if ( e.type === "focusin" && !!isVisible ) {
10153 //if we have jumped to another input clear the time out to cancel the show.
10154 clearTimeout( delayShow );
10155 isVisible = false;
10156 delayHide = setTimeout( function() {
10157 self.hide();
10158 }, 0 );
10159 }
10160 }
10161 });
10162 },
10163
10164 _destroy: function() {
10165 var $el = this.element,
10166 header = $el.is( ".ui-header" );
10167
10168 $el.closest( ".ui-page" ).css( "padding-" + ( header ? "top" : "bottom" ), "" );
10169 $el.removeClass( "ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden" );
10170 $el.closest( ".ui-page" ).removeClass( "ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen" );
10171 }
10172
10173 });
10174
10175 //auto self-init widgets
10176 $.mobile.document
10177 .bind( "pagecreate create", function( e ) {
10178
10179 // DEPRECATED in 1.1: support for data-fullscreen=true|false on the page element.
10180 // This line ensures it still works, but we recommend moving the attribute to the toolbars themselves.
10181 if ( $( e.target ).jqmData( "fullscreen" ) ) {
10182 $( $.mobile.fixedtoolbar.prototype.options.initSelector, e.target ).not( ":jqmData(fullscreen)" ).jqmData( "fullscreen", true );
10183 }
10184
10185 $.mobile.fixedtoolbar.prototype.enhanceWithin( e.target );
10186 });
10187
10188})( jQuery );
10189
10190(function( $, undefined ) {
10191 $.widget( "mobile.fixedtoolbar", $.mobile.fixedtoolbar, {
10192
10193 _create: function() {
10194 this._super();
10195 this._workarounds();
10196 },
10197
10198 //check the browser and version and run needed workarounds
10199 _workarounds: function() {
10200 var ua = navigator.userAgent,
10201 platform = navigator.platform,
10202 // Rendering engine is Webkit, and capture major version
10203 wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
10204 wkversion = !!wkmatch && wkmatch[ 1 ],
10205 os = null,
10206 self = this;
10207 //set the os we are working in if it dosent match one with workarounds return
10208 if( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ){
10209 os = "ios";
10210 } else if( ua.indexOf( "Android" ) > -1 ){
10211 os = "android";
10212 } else {
10213 return;
10214 }
10215 //check os version if it dosent match one with workarounds return
10216 if( os === "ios" ) {
10217 //iOS workarounds
10218 self._bindScrollWorkaround();
10219 } else if( os === "android" && wkversion && wkversion < 534 ) {
10220 //Android 2.3 run all Android 2.3 workaround
10221 self._bindScrollWorkaround();
10222 self._bindListThumbWorkaround();
10223 } else {
10224 return;
10225 }
10226 },
10227
10228 //Utility class for checking header and footer positions relative to viewport
10229 _viewportOffset: function() {
10230 var $el = this.element,
10231 header = $el.is( ".ui-header" ),
10232 offset = Math.abs($el.offset().top - $.mobile.window.scrollTop());
10233 if( !header ) {
10234 offset = Math.round(offset - $.mobile.window.height() + $el.outerHeight())-60;
10235 }
10236 return offset;
10237 },
10238
10239 //bind events for _triggerRedraw() function
10240 _bindScrollWorkaround: function() {
10241 var self = this;
10242 //bind to scrollstop and check if the toolbars are correctly positioned
10243 this._on( $.mobile.window, { scrollstop: function() {
10244 var viewportOffset = self._viewportOffset();
10245 //check if the header is visible and if its in the right place
10246 if( viewportOffset > 2 && self._visible) {
10247 self._triggerRedraw();
10248 }
10249 }});
10250 },
10251
10252 //this addresses issue #4250 Persistent footer instability in v1.1 with long select lists in Android 2.3.3
10253 //and issue #3748 Android 2.x: Page transitions broken when fixed toolbars used
10254 //the absolutely positioned thumbnail in a list view causes problems with fixed position buttons above in a nav bar
10255 //setting the li's to -webkit-transform:translate3d(0,0,0); solves this problem to avoide potential issues in other
10256 //platforms we scope this with the class ui-android-2x-fix
10257 _bindListThumbWorkaround: function() {
10258 this.element.closest(".ui-page").addClass( "ui-android-2x-fixed" );
10259 },
10260 //this addresses issues #4337 Fixed header problem after scrolling content on iOS and Android
10261 //and device bugs project issue #1 Form elements can lose click hit area in position: fixed containers.
10262 //this also addresses not on fixed toolbars page in docs
10263 //adding 1px of padding to the bottom then removing it causes a "redraw"
10264 //which positions the toolbars correctly (they will always be visually correct)
10265 _triggerRedraw: function() {
10266 var paddingBottom = parseFloat( $( ".ui-page-active" ).css( "padding-bottom" ) );
10267 //trigger page redraw to fix incorrectly positioned fixed elements
10268 $( ".ui-page-active" ).css( "padding-bottom", ( paddingBottom + 1 ) +"px" );
10269 //if the padding is reset with out a timeout the reposition will not occure.
10270 //this is independant of JQM the browser seems to need the time to react.
10271 setTimeout( function() {
10272 $( ".ui-page-active" ).css( "padding-bottom", paddingBottom + "px" );
10273 }, 0 );
10274 },
10275
10276 destroy: function() {
10277 this._super();
10278 //Remove the class we added to the page previously in android 2.x
10279 this.element.closest(".ui-page-active").removeClass( "ui-android-2x-fix" );
10280 }
10281 });
10282
10283 })( jQuery );
10284
10285(function( $, undefined ) {
10286
10287$.widget( "mobile.panel", $.mobile.widget, {
10288 options: {
10289 classes: {
10290 panel: "ui-panel",
10291 panelOpen: "ui-panel-open",
10292 panelClosed: "ui-panel-closed",
10293 panelFixed: "ui-panel-fixed",
10294 panelInner: "ui-panel-inner",
10295 modal: "ui-panel-dismiss",
10296 modalOpen: "ui-panel-dismiss-open",
10297 pagePanel: "ui-page-panel",
10298 pagePanelOpen: "ui-page-panel-open",
10299 contentWrap: "ui-panel-content-wrap",
10300 contentWrapOpen: "ui-panel-content-wrap-open",
10301 contentWrapClosed: "ui-panel-content-wrap-closed",
10302 contentFixedToolbar: "ui-panel-content-fixed-toolbar",
10303 contentFixedToolbarOpen: "ui-panel-content-fixed-toolbar-open",
10304 contentFixedToolbarClosed: "ui-panel-content-fixed-toolbar-closed",
10305 animate: "ui-panel-animate"
10306 },
10307 animate: true,
10308 theme: "c",
10309 position: "left",
10310 dismissible: true,
10311 display: "reveal", //accepts reveal, push, overlay
10312 initSelector: ":jqmData(role='panel')",
10313 swipeClose: true,
10314 positionFixed: false
10315 },
10316
10317 _panelID: null,
10318 _closeLink: null,
10319 _page: null,
10320 _modal: null,
10321 _panelInner: null,
10322 _wrapper: null,
10323 _fixedToolbar: null,
10324
10325 _create: function() {
10326 var self = this,
10327 $el = self.element,
10328 page = $el.closest( ":jqmData(role='page')" ),
10329 _getPageTheme = function() {
10330 var $theme = $.data( page[0], "mobilePage" ).options.theme,
10331 $pageThemeClass = "ui-body-" + $theme;
10332 return $pageThemeClass;
10333 },
10334 _getPanelInner = function() {
10335 var $panelInner = $el.find( "." + self.options.classes.panelInner );
10336 if ( $panelInner.length === 0 ) {
10337 $panelInner = $el.children().wrapAll( '<div class="' + self.options.classes.panelInner + '" />' ).parent();
10338 }
10339 return $panelInner;
10340 },
10341 _getWrapper = function() {
10342 var $wrapper = page.find( "." + self.options.classes.contentWrap );
10343 if ( $wrapper.length === 0 ) {
10344 $wrapper = page.children( ".ui-header:not(:jqmData(position='fixed')), .ui-content:not(:jqmData(role='popup')), .ui-footer:not(:jqmData(position='fixed'))" ).wrapAll( '<div class="' + self.options.classes.contentWrap + ' ' + _getPageTheme() + '" />' ).parent();
10345 if ( $.support.cssTransform3d && !!self.options.animate ) {
10346 $wrapper.addClass( self.options.classes.animate );
10347 }
10348 }
10349 return $wrapper;
10350 },
10351 _getFixedToolbar = function() {
10352 var $fixedToolbar = page.find( "." + self.options.classes.contentFixedToolbar );
10353 if ( $fixedToolbar.length === 0 ) {
10354 $fixedToolbar = page.find( ".ui-header:jqmData(position='fixed'), .ui-footer:jqmData(position='fixed')" ).addClass( self.options.classes.contentFixedToolbar );
10355 if ( $.support.cssTransform3d && !!self.options.animate ) {
10356 $fixedToolbar.addClass( self.options.classes.animate );
10357 }
10358 }
10359 return $fixedToolbar;
10360 };
10361
10362 // expose some private props to other methods
10363 $.extend( this, {
10364 _panelID: $el.attr( "id" ),
10365 _closeLink: $el.find( ":jqmData(rel='close')" ),
10366 _page: $el.closest( ":jqmData(role='page')" ),
10367 _pageTheme: _getPageTheme(),
10368 _panelInner: _getPanelInner(),
10369 _wrapper: _getWrapper(),
10370 _fixedToolbar: _getFixedToolbar()
10371 });
10372
10373 self._addPanelClasses();
10374 self._wrapper.addClass( this.options.classes.contentWrapClosed );
10375 self._fixedToolbar.addClass( this.options.classes.contentFixedToolbarClosed );
10376 // add class to page so we can set "overflow-x: hidden;" for it to fix Android zoom issue
10377 self._page.addClass( self.options.classes.pagePanel );
10378
10379 // if animating, add the class to do so
10380 if ( $.support.cssTransform3d && !!self.options.animate ) {
10381 this.element.addClass( self.options.classes.animate );
10382 }
10383
10384 self._bindUpdateLayout();
10385 self._bindCloseEvents();
10386 self._bindLinkListeners();
10387 self._bindPageEvents();
10388
10389 if ( !!self.options.dismissible ) {
10390 self._createModal();
10391 }
10392
10393 self._bindSwipeEvents();
10394 },
10395
10396 _createModal: function( options ) {
10397 var self = this;
10398
10399 self._modal = $( "<div class='" + self.options.classes.modal + "' data-panelid='" + self._panelID + "'></div>" )
10400 .on( "mousedown", function() {
10401 self.close();
10402 })
10403 .appendTo( this._page );
10404 },
10405
10406 _getPosDisplayClasses: function( prefix ) {
10407 return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
10408 },
10409
10410 _getPanelClasses: function() {
10411 var panelClasses = this.options.classes.panel +
10412 " " + this._getPosDisplayClasses( this.options.classes.panel ) +
10413 " " + this.options.classes.panelClosed;
10414
10415 if ( this.options.theme ) {
10416 panelClasses += " ui-body-" + this.options.theme;
10417 }
10418 if ( !!this.options.positionFixed ) {
10419 panelClasses += " " + this.options.classes.panelFixed;
10420 }
10421 return panelClasses;
10422 },
10423
10424 _addPanelClasses: function() {
10425 this.element.addClass( this._getPanelClasses() );
10426 },
10427
10428 _bindCloseEvents: function() {
10429 var self = this;
10430
10431 self._closeLink.on( "click.panel" , function( e ) {
10432 e.preventDefault();
10433 self.close();
10434 return false;
10435 });
10436 self.element.on( "click.panel" , "a:jqmData(ajax='false')", function( e ) {
10437 self.close();
10438 });
10439 },
10440
10441 _positionPanel: function() {
10442 var self = this,
10443 panelInnerHeight = self._panelInner.outerHeight(),
10444 expand = panelInnerHeight > $.mobile.getScreenHeight();
10445
10446 if ( expand || !self.options.positionFixed ) {
10447 if ( expand ) {
10448 self._unfixPanel();
10449 $.mobile.resetActivePageHeight( panelInnerHeight );
10450 }
10451 self._scrollIntoView( panelInnerHeight );
10452 } else {
10453 self._fixPanel();
10454 }
10455 },
10456
10457 _scrollIntoView: function( panelInnerHeight ) {
10458 if ( panelInnerHeight < $( window ).scrollTop() ) {
10459 window.scrollTo( 0, 0 );
10460 }
10461 },
10462
10463 _bindFixListener: function() {
10464 this._on( $( window ), { "throttledresize": "_positionPanel" });
10465 },
10466
10467 _unbindFixListener: function() {
10468 this._off( $( window ), "throttledresize" );
10469 },
10470
10471 _unfixPanel: function() {
10472 if ( !!this.options.positionFixed && $.support.fixedPosition ) {
10473 this.element.removeClass( this.options.classes.panelFixed );
10474 }
10475 },
10476
10477 _fixPanel: function() {
10478 if ( !!this.options.positionFixed && $.support.fixedPosition ) {
10479 this.element.addClass( this.options.classes.panelFixed );
10480 }
10481 },
10482
10483 _bindUpdateLayout: function() {
10484 var self = this;
10485
10486 self.element.on( "updatelayout", function( e ) {
10487 if ( self._open ) {
10488 self._positionPanel();
10489 }
10490 });
10491 },
10492
10493 _bindLinkListeners: function() {
10494 var self = this;
10495
10496 self._page.on( "click.panel" , "a", function( e ) {
10497 if ( this.href.split( "#" )[ 1 ] === self._panelID && self._panelID !== undefined ) {
10498 e.preventDefault();
10499 var $link = $( this ),
10500 $parent;
10501 if ( ! $link.hasClass( "ui-link" ) ) {
10502 // Check if we are in a listview
10503 $parent = $link.parent().parent();
10504 if ( $parent.hasClass( "ui-li" ) ) {
10505 $link = $parent.parent();
10506 }
10507 $link.addClass( $.mobile.activeBtnClass );
10508 self.element.one( "panelopen panelclose", function() {
10509 $link.removeClass( $.mobile.activeBtnClass );
10510 });
10511 }
10512 self.toggle();
10513 return false;
10514 }
10515 });
10516 },
10517
10518 _bindSwipeEvents: function() {
10519 var self = this,
10520 area = self._modal ? self.element.add( self._modal ) : self.element;
10521
10522 // on swipe, close the panel
10523 if( !!self.options.swipeClose ) {
10524 if ( self.options.position === "left" ) {
10525 area.on( "swipeleft.panel", function( e ) {
10526 self.close();
10527 });
10528 } else {
10529 area.on( "swiperight.panel", function( e ) {
10530 self.close();
10531 });
10532 }
10533 }
10534 },
10535
10536 _bindPageEvents: function() {
10537 var self = this;
10538
10539 self._page
10540 // Close the panel if another panel on the page opens
10541 .on( "panelbeforeopen", function( e ) {
10542 if ( self._open && e.target !== self.element[ 0 ] ) {
10543 self.close();
10544 }
10545 })
10546 // clean up open panels after page hide
10547 .on( "pagehide", function( e ) {
10548 if ( self._open ) {
10549 self.close( true );
10550 }
10551 })
10552 // on escape, close? might need to have a target check too...
10553 .on( "keyup.panel", function( e ) {
10554 if ( e.keyCode === 27 && self._open ) {
10555 self.close();
10556 }
10557 });
10558 },
10559
10560 // state storage of open or closed
10561 _open: false,
10562
10563 _contentWrapOpenClasses: null,
10564 _fixedToolbarOpenClasses: null,
10565 _modalOpenClasses: null,
10566
10567 open: function( immediate ) {
10568 if ( !this._open ) {
10569 var self = this,
10570 o = self.options,
10571 _openPanel = function() {
10572 self._page.off( "panelclose" );
10573 self._page.jqmData( "panel", "open" );
10574
10575 if ( !immediate && $.support.cssTransform3d && !!o.animate ) {
10576 self.element.add( self._wrapper ).on( self._transitionEndEvents, complete );
10577 } else {
10578 setTimeout( complete, 0 );
10579 }
10580
10581 if ( self.options.theme && self.options.display !== "overlay" ) {
10582 self._page
10583 .removeClass( self._pageTheme )
10584 .addClass( "ui-body-" + self.options.theme );
10585 }
10586
10587 self.element.removeClass( o.classes.panelClosed ).addClass( o.classes.panelOpen );
10588
10589 self._positionPanel();
10590
10591 // Fix for IE7 min-height bug
10592 if ( self.options.theme && self.options.display !== "overlay" ) {
10593 self._wrapper.css( "min-height", self._page.css( "min-height" ) );
10594 }
10595
10596 self._contentWrapOpenClasses = self._getPosDisplayClasses( o.classes.contentWrap );
10597 self._wrapper
10598 .removeClass( o.classes.contentWrapClosed )
10599 .addClass( self._contentWrapOpenClasses + " " + o.classes.contentWrapOpen );
10600
10601 self._fixedToolbarOpenClasses = self._getPosDisplayClasses( o.classes.contentFixedToolbar );
10602 self._fixedToolbar
10603 .removeClass( o.classes.contentFixedToolbarClosed )
10604 .addClass( self._fixedToolbarOpenClasses + " " + o.classes.contentFixedToolbarOpen );
10605
10606 self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
10607 if ( self._modal ) {
10608 self._modal.addClass( self._modalOpenClasses );
10609 }
10610 },
10611 complete = function() {
10612 self.element.add( self._wrapper ).off( self._transitionEndEvents, complete );
10613
10614 self._page.addClass( o.classes.pagePanelOpen );
10615
10616 self._bindFixListener();
10617
10618 self._trigger( "open" );
10619 };
10620
10621 if ( this.element.closest( ".ui-page-active" ).length < 0 ) {
10622 immediate = true;
10623 }
10624
10625 self._trigger( "beforeopen" );
10626
10627 if ( self._page.jqmData('panel') === "open" ) {
10628 self._page.on( "panelclose", function() {
10629 _openPanel();
10630 });
10631 } else {
10632 _openPanel();
10633 }
10634
10635 self._open = true;
10636 }
10637 },
10638
10639 close: function( immediate ) {
10640 if ( this._open ) {
10641 var o = this.options,
10642 self = this,
10643 _closePanel = function() {
10644 if ( !immediate && $.support.cssTransform3d && !!o.animate ) {
10645 self.element.add( self._wrapper ).on( self._transitionEndEvents, complete );
10646 } else {
10647 setTimeout( complete, 0 );
10648 }
10649
10650 self._page.removeClass( o.classes.pagePanelOpen );
10651 self.element.removeClass( o.classes.panelOpen );
10652 self._wrapper.removeClass( o.classes.contentWrapOpen );
10653 self._fixedToolbar.removeClass( o.classes.contentFixedToolbarOpen );
10654
10655 if ( self._modal ) {
10656 self._modal.removeClass( self._modalOpenClasses );
10657 }
10658 },
10659 complete = function() {
10660 if ( self.options.theme && self.options.display !== "overlay" ) {
10661 self._page.removeClass( "ui-body-" + self.options.theme ).addClass( self._pageTheme );
10662 // reset fix for IE7 min-height bug
10663 self._wrapper.css( "min-height", "" );
10664 }
10665 self.element.add( self._wrapper ).off( self._transitionEndEvents, complete );
10666 self.element.addClass( o.classes.panelClosed );
10667
10668 self._wrapper
10669 .removeClass( self._contentWrapOpenClasses )
10670 .addClass( o.classes.contentWrapClosed );
10671
10672 self._fixedToolbar
10673 .removeClass( self._fixedToolbarOpenClasses )
10674 .addClass( o.classes.contentFixedToolbarClosed );
10675
10676 self._fixPanel();
10677 self._unbindFixListener();
10678 $.mobile.resetActivePageHeight();
10679
10680 self._page.jqmRemoveData( "panel" );
10681 self._trigger( "close" );
10682 };
10683
10684 if ( this.element.closest( ".ui-page-active" ).length < 0 ) {
10685 immediate = true;
10686 }
10687 self._trigger( "beforeclose" );
10688
10689 _closePanel();
10690
10691 self._open = false;
10692 }
10693 },
10694
10695 toggle: function( options ) {
10696 this[ this._open ? "close" : "open" ]();
10697 },
10698
10699 _transitionEndEvents: "webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",
10700
10701 _destroy: function() {
10702 var classes = this.options.classes,
10703 theme = this.options.theme,
10704 hasOtherSiblingPanels = this.element.siblings( "." + classes.panel ).length;
10705
10706 // create
10707 if ( !hasOtherSiblingPanels ) {
10708 this._wrapper.children().unwrap();
10709 this._page.find( "a" ).unbind( "panelopen panelclose" );
10710 this._page.removeClass( classes.pagePanel );
10711 if ( this._open ) {
10712 this._page.jqmRemoveData( "panel" );
10713 this._page.removeClass( classes.pagePanelOpen );
10714 if ( theme ) {
10715 this._page.removeClass( "ui-body-" + theme ).addClass( this._pageTheme );
10716 }
10717 $.mobile.resetActivePageHeight();
10718 }
10719 } else if ( this._open ) {
10720 this._wrapper.removeClass( classes.contentWrapOpen );
10721 this._fixedToolbar.removeClass( classes.contentFixedToolbarOpen );
10722 this._page.jqmRemoveData( "panel" );
10723 this._page.removeClass( classes.pagePanelOpen );
10724 if ( theme ) {
10725 this._page.removeClass( "ui-body-" + theme ).addClass( this._pageTheme );
10726 }
10727 }
10728
10729 this._panelInner.children().unwrap();
10730
10731 this.element.removeClass( [ this._getPanelClasses(), classes.panelAnimate ].join( " " ) )
10732 .off( "swipeleft.panel swiperight.panel" )
10733 .off( "panelbeforeopen" )
10734 .off( "panelhide" )
10735 .off( "keyup.panel" )
10736 .off( "updatelayout" );
10737
10738 this._closeLink.off( "click.panel" );
10739
10740 if ( this._modal ) {
10741 this._modal.remove();
10742 }
10743
10744 // open and close
10745 this.element.off( this._transitionEndEvents )
10746 .removeClass( [ classes.panelUnfixed, classes.panelClosed, classes.panelOpen ].join( " " ) );
10747 }
10748});
10749
10750//auto self-init widgets
10751$( document ).bind( "pagecreate create", function( e ) {
10752 $.mobile.panel.prototype.enhanceWithin( e.target );
10753});
10754
10755})( jQuery );
10756
10757(function( $, undefined ) {
10758
10759$.widget( "mobile.table", $.mobile.widget, {
10760
10761 options: {
10762 classes: {
10763 table: "ui-table"
10764 },
10765 initSelector: ":jqmData(role='table')"
10766 },
10767
10768 _create: function() {
10769 var self = this;
10770 self.refresh( true );
10771 },
10772
10773 refresh: function (create) {
10774 var self = this,
10775 trs = this.element.find( "thead tr" );
10776
10777 if ( create ) {
10778 this.element.addClass( this.options.classes.table );
10779 }
10780
10781 // Expose headers and allHeaders properties on the widget
10782 // headers references the THs within the first TR in the table
10783 self.headers = this.element.find( "tr:eq(0)" ).children();
10784
10785 // allHeaders references headers, plus all THs in the thead, which may include several rows, or not
10786 self.allHeaders = self.headers.add( trs.children() );
10787
10788 trs.each(function(){
10789
10790 var coltally = 0;
10791
10792 $( this ).children().each(function( i ){
10793
10794 var span = parseInt( $( this ).attr( "colspan" ), 10 ),
10795 sel = ":nth-child(" + ( coltally + 1 ) + ")";
10796 $( this )
10797 .jqmData( "colstart", coltally + 1 );
10798
10799 if( span ){
10800 for( var j = 0; j < span - 1; j++ ){
10801 coltally++;
10802 sel += ", :nth-child(" + ( coltally + 1 ) + ")";
10803 }
10804 }
10805
10806 if ( create === undefined ) {
10807 $(this).jqmData("cells", "");
10808 }
10809 // Store "cells" data on header as a reference to all cells in the same column as this TH
10810 $( this )
10811 .jqmData( "cells", self.element.find( "tr" ).not( trs.eq(0) ).not( this ).children( sel ) );
10812
10813 coltally++;
10814
10815 });
10816
10817 });
10818
10819 // update table modes
10820 if ( create === undefined ) {
10821 this.element.trigger( 'refresh' );
10822 }
10823 }
10824
10825});
10826
10827//auto self-init widgets
10828$.mobile.document.bind( "pagecreate create", function( e ) {
10829 $.mobile.table.prototype.enhanceWithin( e.target );
10830});
10831
10832})( jQuery );
10833
10834
10835(function( $, undefined ) {
10836
10837$.mobile.table.prototype.options.mode = "columntoggle";
10838
10839$.mobile.table.prototype.options.columnBtnTheme = null;
10840
10841$.mobile.table.prototype.options.columnPopupTheme = null;
10842
10843$.mobile.table.prototype.options.columnBtnText = "Columns...";
10844
10845$.mobile.table.prototype.options.classes = $.extend(
10846 $.mobile.table.prototype.options.classes,
10847 {
10848 popup: "ui-table-columntoggle-popup",
10849 columnBtn: "ui-table-columntoggle-btn",
10850 priorityPrefix: "ui-table-priority-",
10851 columnToggleTable: "ui-table-columntoggle"
10852 }
10853);
10854
10855$.mobile.document.delegate( ":jqmData(role='table')", "tablecreate refresh", function( e ) {
10856
10857 var $table = $( this ),
10858 self = $table.data( "mobile-table" ),
10859 event = e.type,
10860 o = self.options,
10861 ns = $.mobile.ns,
10862 id = ( $table.attr( "id" ) || o.classes.popup ) + "-popup", /* TODO BETTER FALLBACK ID HERE */
10863 $menuButton,
10864 $popup,
10865 $menu,
10866 $switchboard;
10867
10868 if ( o.mode !== "columntoggle" ) {
10869 return;
10870 }
10871
10872 if ( event !== "refresh" ) {
10873 self.element.addClass( o.classes.columnToggleTable );
10874
10875 $menuButton = $( "<a href='#" + id + "' class='" + o.classes.columnBtn + "' data-" + ns + "rel='popup' data-" + ns + "mini='true'>" + o.columnBtnText + "</a>" ),
10876 $popup = $( "<div data-" + ns + "role='popup' data-" + ns + "role='fieldcontain' class='" + o.classes.popup + "' id='" + id + "'></div>"),
10877 $menu = $("<fieldset data-" + ns + "role='controlgroup'></fieldset>");
10878 }
10879
10880 // create the hide/show toggles
10881 self.headers.not( "td" ).each(function( i ) {
10882
10883 var priority = $( this ).jqmData( "priority" ),
10884 $cells = $( this ).add( $( this ).jqmData( "cells" ) );
10885
10886 if ( priority ) {
10887
10888 $cells.addClass( o.classes.priorityPrefix + priority );
10889
10890 if ( event !== "refresh" ) {
10891 $("<label><input type='checkbox' checked />" + $( this ).text() + "</label>" )
10892 .appendTo( $menu )
10893 .children( 0 )
10894 .jqmData( "cells", $cells )
10895 .checkboxradio({
10896 theme: o.columnPopupTheme
10897 });
10898 } else {
10899 $( '#' + id + ' fieldset div:eq(' + i +')').find('input').jqmData( 'cells', $cells );
10900 }
10901 }
10902 });
10903
10904 if ( event !== "refresh" ) {
10905 $menu.appendTo( $popup );
10906 }
10907
10908 // bind change event listeners to inputs - TODO: move to a private method?
10909 if ( $menu === undefined ) {
10910 $switchboard = $('#' + id + ' fieldset');
10911 } else {
10912 $switchboard = $menu;
10913 }
10914
10915 if ( event !== "refresh" ) {
10916 $switchboard.on( "change", "input", function( e ){
10917 if( this.checked ){
10918 $( this ).jqmData( "cells" ).removeClass( "ui-table-cell-hidden" ).addClass( "ui-table-cell-visible" );
10919 } else {
10920 $( this ).jqmData( "cells" ).removeClass( "ui-table-cell-visible" ).addClass( "ui-table-cell-hidden" );
10921 }
10922 });
10923
10924 $menuButton
10925 .insertBefore( $table )
10926 .buttonMarkup({
10927 theme: o.columnBtnTheme
10928 });
10929
10930 $popup
10931 .insertBefore( $table )
10932 .popup();
10933 }
10934
10935 // refresh method
10936 self.update = function(){
10937 $switchboard.find( "input" ).each( function(){
10938 if (this.checked) {
10939 this.checked = $( this ).jqmData( "cells" ).eq(0).css( "display" ) === "table-cell";
10940 if (event === "refresh") {
10941 $( this ).jqmData( "cells" ).addClass('ui-table-cell-visible');
10942 }
10943 } else {
10944 $( this ).jqmData( "cells" ).addClass('ui-table-cell-hidden');
10945 }
10946 $( this ).checkboxradio( "refresh" );
10947 });
10948 };
10949
10950 $.mobile.window.on( "throttledresize", self.update );
10951
10952 self.update();
10953
10954});
10955
10956})( jQuery );
10957
10958(function( $, undefined ) {
10959
10960$.mobile.table.prototype.options.mode = "reflow";
10961
10962$.mobile.table.prototype.options.classes = $.extend(
10963 $.mobile.table.prototype.options.classes,
10964 {
10965 reflowTable: "ui-table-reflow",
10966 cellLabels: "ui-table-cell-label"
10967 }
10968);
10969
10970$.mobile.document.delegate( ":jqmData(role='table')", "tablecreate refresh", function( e ) {
10971
10972 var $table = $( this ),
10973 event = e.type,
10974 self = $table.data( "mobile-table" ),
10975 o = self.options;
10976
10977 // If it's not reflow mode, return here.
10978 if( o.mode !== "reflow" ){
10979 return;
10980 }
10981
10982 if ( event !== "refresh" ) {
10983 self.element.addClass( o.classes.reflowTable );
10984 }
10985
10986 // get headers in reverse order so that top-level headers are appended last
10987 var reverseHeaders = $( self.allHeaders.get().reverse() );
10988
10989 // create the hide/show toggles
10990 reverseHeaders.each(function( i ){
10991 var $cells = $( this ).jqmData( "cells" ),
10992 colstart = $( this ).jqmData( "colstart" ),
10993 hierarchyClass = $cells.not( this ).filter( "thead th" ).length && " ui-table-cell-label-top",
10994 text = $(this).text();
10995
10996 if( text !== "" ){
10997
10998 if( hierarchyClass ){
10999 var iteration = parseInt( $( this ).attr( "colspan" ), 10 ),
11000 filter = "";
11001
11002 if( iteration ){
11003 filter = "td:nth-child("+ iteration +"n + " + ( colstart ) +")";
11004 }
11005 $cells.filter( filter ).prepend( "<b class='" + o.classes.cellLabels + hierarchyClass + "'>" + text + "</b>" );
11006 }
11007 else {
11008 $cells.prepend( "<b class='" + o.classes.cellLabels + "'>" + text + "</b>" );
11009 }
11010
11011 }
11012 });
11013
11014});
11015
11016})( jQuery );
11017
11018(function( $, window ) {
11019
11020 $.mobile.iosorientationfixEnabled = true;
11021
11022 // This fix addresses an iOS bug, so return early if the UA claims it's something else.
11023 var ua = navigator.userAgent;
11024 if( !( /iPhone|iPad|iPod/.test( navigator.platform ) && /OS [1-5]_[0-9_]* like Mac OS X/i.test( ua ) && ua.indexOf( "AppleWebKit" ) > -1 ) ){
11025 $.mobile.iosorientationfixEnabled = false;
11026 return;
11027 }
11028
11029 var zoom = $.mobile.zoom,
11030 evt, x, y, z, aig;
11031
11032 function checkTilt( e ) {
11033 evt = e.originalEvent;
11034 aig = evt.accelerationIncludingGravity;
11035
11036 x = Math.abs( aig.x );
11037 y = Math.abs( aig.y );
11038 z = Math.abs( aig.z );
11039
11040 // If portrait orientation and in one of the danger zones
11041 if ( !window.orientation && ( x > 7 || ( ( z > 6 && y < 8 || z < 8 && y > 6 ) && x > 5 ) ) ) {
11042 if ( zoom.enabled ) {
11043 zoom.disable();
11044 }
11045 } else if ( !zoom.enabled ) {
11046 zoom.enable();
11047 }
11048 }
11049
11050 $.mobile.document.on( "mobileinit", function(){
11051 if( $.mobile.iosorientationfixEnabled ){
11052 $.mobile.window
11053 .bind( "orientationchange.iosorientationfix", zoom.enable )
11054 .bind( "devicemotion.iosorientationfix", checkTilt );
11055 }
11056 });
11057
11058}( jQuery, this ));
11059
11060(function( $, window, undefined ) {
11061 var $html = $( "html" ),
11062 $head = $( "head" ),
11063 $window = $.mobile.window;
11064
11065 //remove initial build class (only present on first pageshow)
11066 function hideRenderingClass() {
11067 $html.removeClass( "ui-mobile-rendering" );
11068 }
11069
11070 // trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
11071 $( window.document ).trigger( "mobileinit" );
11072
11073 // support conditions
11074 // if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
11075 // otherwise, proceed with the enhancements
11076 if ( !$.mobile.gradeA() ) {
11077 return;
11078 }
11079
11080 // override ajaxEnabled on platforms that have known conflicts with hash history updates
11081 // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
11082 if ( $.mobile.ajaxBlacklist ) {
11083 $.mobile.ajaxEnabled = false;
11084 }
11085
11086 // Add mobile, initial load "rendering" classes to docEl
11087 $html.addClass( "ui-mobile ui-mobile-rendering" );
11088
11089 // This is a fallback. If anything goes wrong (JS errors, etc), or events don't fire,
11090 // this ensures the rendering class is removed after 5 seconds, so content is visible and accessible
11091 setTimeout( hideRenderingClass, 5000 );
11092
11093 $.extend( $.mobile, {
11094 // find and enhance the pages in the dom and transition to the first page.
11095 initializePage: function() {
11096 // find present pages
11097 var path = $.mobile.path,
11098 $pages = $( ":jqmData(role='page'), :jqmData(role='dialog')" ),
11099 hash = path.stripHash( path.stripQueryParams(path.parseLocation().hash) ),
11100 hashPage = document.getElementById( hash );
11101
11102 // if no pages are found, create one with body's inner html
11103 if ( !$pages.length ) {
11104 $pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
11105 }
11106
11107 // add dialogs, set data-url attrs
11108 $pages.each(function() {
11109 var $this = $( this );
11110
11111 // unless the data url is already set set it to the pathname
11112 if ( !$this.jqmData( "url" ) ) {
11113 $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) || location.pathname + location.search );
11114 }
11115 });
11116
11117 // define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
11118 $.mobile.firstPage = $pages.first();
11119
11120 // define page container
11121 $.mobile.pageContainer = $.mobile.firstPage.parent().addClass( "ui-mobile-viewport" );
11122
11123 // initialize navigation events now, after mobileinit has occurred and the page container
11124 // has been created but before the rest of the library is alerted to that fact
11125 $.mobile.navreadyDeferred.resolve();
11126
11127 // alert listeners that the pagecontainer has been determined for binding
11128 // to events triggered on it
11129 $window.trigger( "pagecontainercreate" );
11130
11131 // cue page loading message
11132 $.mobile.showPageLoadingMsg();
11133
11134 //remove initial build class (only present on first pageshow)
11135 hideRenderingClass();
11136
11137 // if hashchange listening is disabled, there's no hash deeplink,
11138 // the hash is not valid (contains more than one # or does not start with #)
11139 // or there is no page with that hash, change to the first page in the DOM
11140 // Remember, however, that the hash can also be a path!
11141 if ( ! ( $.mobile.hashListeningEnabled &&
11142 $.mobile.path.isHashValid( location.hash ) &&
11143 ( $( hashPage ).is( ':jqmData(role="page")' ) ||
11144 $.mobile.path.isPath( hash ) ||
11145 hash === $.mobile.dialogHashKey ) ) ) {
11146
11147 // Store the initial destination
11148 if ( $.mobile.path.isHashValid( location.hash ) ) {
11149 $.mobile.urlHistory.initialDst = hash.replace( "#", "" );
11150 }
11151
11152 // make sure to set initial popstate state if it exists
11153 // so that navigation back to the initial page works properly
11154 if( $.event.special.navigate.isPushStateEnabled() ) {
11155 $.mobile.navigate.navigator.squash( path.parseLocation().href );
11156 }
11157
11158 $.mobile.changePage( $.mobile.firstPage, {
11159 transition: "none",
11160 reverse: true,
11161 changeHash: false,
11162 fromHashChange: true
11163 });
11164 } else {
11165 // trigger hashchange or navigate to squash and record the correct
11166 // history entry for an initial hash path
11167 if( !$.event.special.navigate.isPushStateEnabled() ) {
11168 $window.trigger( "hashchange", [true] );
11169 } else {
11170 // TODO figure out how to simplify this interaction with the initial history entry
11171 // at the bottom js/navigate/navigate.js
11172 $.mobile.navigate.history.stack = [];
11173 $.mobile.navigate( $.mobile.path.isPath( location.hash ) ? location.hash : location.href );
11174 }
11175 }
11176 }
11177 });
11178
11179 // check which scrollTop value should be used by scrolling to 1 immediately at domready
11180 // then check what the scroll top is. Android will report 0... others 1
11181 // note that this initial scroll won't hide the address bar. It's just for the check.
11182 $(function() {
11183 window.scrollTo( 0, 1 );
11184
11185 // if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
11186 // it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
11187 // so if it's 1, use 0 from now on
11188 $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $.mobile.window.scrollTop() === 1 ) ? 0 : 1;
11189
11190 //dom-ready inits
11191 if ( $.mobile.autoInitializePage ) {
11192 $.mobile.initializePage();
11193 }
11194
11195 // window load event
11196 // hide iOS browser chrome on load
11197 $window.load( $.mobile.silentScroll );
11198
11199 if ( !$.support.cssPointerEvents ) {
11200 // IE and Opera don't support CSS pointer-events: none that we use to disable link-based buttons
11201 // by adding the 'ui-disabled' class to them. Using a JavaScript workaround for those browser.
11202 // https://github.com/jquery/jquery-mobile/issues/3558
11203
11204 $.mobile.document.delegate( ".ui-disabled", "vclick",
11205 function( e ) {
11206 e.preventDefault();
11207 e.stopImmediatePropagation();
11208 }
11209 );
11210 }
11211 });
11212}( jQuery, this ));
11213
11214
11215}));
diff --git a/static/vendor/jquery.mobile.structure-1.3.2.css b/static/vendor/jquery.mobile.structure-1.3.2.css
deleted file mode 100644
index 11573c6..0000000
--- a/static/vendor/jquery.mobile.structure-1.3.2.css
+++ /dev/null
@@ -1,2314 +0,0 @@
1/*!
2* jQuery Mobile 1.3.2
3* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
4* http://jquerymobile.com
5*
6* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
7* Released under the MIT license.
8* http://jquery.org/license
9*
10*/
11
12
13/* some unsets - more probably needed */
14.ui-mobile, .ui-mobile body { height: 99.9%; }
15.ui-mobile fieldset, .ui-page { padding: 0; margin: 0; }
16.ui-mobile a img, .ui-mobile fieldset { border-width: 0; }
17.ui-mobile fieldset { min-width: 0; }
18/* responsive page widths */
19.ui-mobile-viewport { margin: 0; overflow-x: visible; -webkit-text-size-adjust: 100%; -ms-text-size-adjust:none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
20/* Issue #2066 */
21body.ui-mobile-viewport,
22div.ui-mobile-viewport { overflow-x: hidden; }
23/* "page" containers - full-screen views, one should always be in view post-pageload */
24.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; }
25.ui-mobile .ui-page-active { display: block; overflow: visible; }
26/* on ios4, setting focus on the page element causes flashing during transitions when there is an outline, so we turn off outlines */
27.ui-page { outline: none; }
28/*orientations from js are available */
29@media screen and (orientation: portrait){
30.ui-mobile .ui-page { min-height: 420px; }
31}
32@media screen and (orientation: landscape){
33.ui-mobile .ui-page { min-height: 300px; }
34}
35/* loading screen */
36.ui-loading .ui-loader { display: block; }
37.ui-loader { display: none; z-index: 9999999; position: fixed; top: 50%; left: 50%; border:0; }
38.ui-loader-default { background: none; filter: Alpha(Opacity=18); opacity: .18; width: 46px; height: 46px; margin-left: -23px; margin-top: -23px; }
39.ui-loader-verbose { width: 200px; filter: Alpha(Opacity=88); opacity: .88; box-shadow: 0 1px 1px -1px #fff; height: auto; margin-left: -110px; margin-top: -43px; padding: 10px; }
40.ui-loader-default h1 { font-size: 0; width: 0; height: 0; overflow: hidden; }
41.ui-loader-verbose h1 { font-size: 16px; margin: 0; text-align: center; }
42.ui-loader .ui-icon { background-color: #000; display: block; margin: 0; width: 44px; height: 44px; padding: 1px; -webkit-border-radius: 36px; border-radius: 36px; }
43.ui-loader-verbose .ui-icon { margin: 0 auto 10px; filter: Alpha(Opacity=75); opacity: .75; }
44.ui-loader-textonly { padding: 15px; margin-left: -115px; }
45.ui-loader-textonly .ui-icon { display: none; }
46.ui-loader-fakefix { position: absolute; }
47/*fouc*/
48.ui-mobile-rendering > * { visibility: hidden; }
49/*headers, content panels*/
50.ui-bar, .ui-body { position: relative; padding: .4em 15px; overflow: hidden; display: block; clear:both; }
51.ui-bar { font-size: 16px; margin: 0; }
52.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; }
53.ui-header, .ui-footer { position: relative; zoom: 1; }
54.ui-mobile .ui-header, .ui-mobile .ui-footer { border-left-width: 0; border-right-width: 0; }
55.ui-header .ui-btn-left,
56.ui-header .ui-btn-right,
57.ui-footer .ui-btn-left,
58.ui-footer .ui-btn-right,
59.ui-header-fixed.ui-fixed-hidden .ui-btn-left,
60.ui-header-fixed.ui-fixed-hidden .ui-btn-right { position: absolute; top: 3px; }
61.ui-header-fixed .ui-btn-left,
62.ui-header-fixed .ui-btn-right { top: 4px;}
63.ui-header .ui-btn-left,
64.ui-footer .ui-btn-left { left: 5px; }
65.ui-header .ui-btn-right,
66.ui-footer .ui-btn-right { right: 5px; }
67.ui-footer > .ui-btn-icon-notext,
68.ui-header > .ui-btn-icon-notext,
69.ui-header-fixed.ui-fixed-hidden > .ui-btn-icon-notext { top: 6px; }
70.ui-header-fixed > .ui-btn-icon-notext { top: 7px;}
71.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; }
72.ui-footer .ui-title { margin: .6em 15px .8em; }
73/* content area*/
74.ui-content { border-width: 0; overflow: visible; overflow-x: hidden; padding: 15px; }
75/* corner styling for dialogs and popups */
76.ui-corner-all > .ui-header:first-child,
77.ui-corner-all > .ui-content:first-child,
78.ui-corner-all > .ui-footer:first-child {
79 -webkit-border-top-left-radius: inherit;
80 border-top-left-radius: inherit;
81 -webkit-border-top-right-radius: inherit;
82 border-top-right-radius: inherit;
83}
84.ui-corner-all > .ui-header:last-child,
85.ui-corner-all > .ui-content:last-child,
86.ui-corner-all > .ui-footer:last-child {
87 -webkit-border-bottom-left-radius: inherit;
88 border-bottom-left-radius: inherit;
89 -webkit-border-bottom-right-radius: inherit;
90 border-bottom-right-radius: inherit;
91}
92/* icons sizing */
93.ui-icon { width: 18px; height: 18px; }
94/* non-js content hiding */
95.ui-nojs { position: absolute; left: -9999px; }
96/* accessible content hiding */
97.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,
98.ui-hidden-accessible { position: absolute !important; left: -9999px; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
99/* Transitions originally inspired by those from jQtouch, nice work, folks */
100.ui-mobile-viewport-transitioning,
101.ui-mobile-viewport-transitioning .ui-page {
102 width: 100%;
103 height: 100%;
104 overflow: hidden;
105 -webkit-box-sizing: border-box;
106 -moz-box-sizing: border-box;
107 box-sizing: border-box;
108}
109.ui-page-pre-in {
110 opacity: 0;
111}
112.in {
113 -webkit-animation-timing-function: ease-out;
114 -webkit-animation-duration: 350ms;
115 -moz-animation-timing-function: ease-out;
116 -moz-animation-duration: 350ms;
117 animation-timing-function: ease-out;
118 animation-duration: 350ms;
119}
120.out {
121 -webkit-animation-timing-function: ease-in;
122 -webkit-animation-duration: 225ms;
123 -moz-animation-timing-function: ease-in;
124 -moz-animation-duration: 225ms;
125 animation-timing-function: ease-in;
126 animation-duration: 225ms;
127}
128@-webkit-keyframes fadein {
129 from { opacity: 0; }
130 to { opacity: 1; }
131}
132@-moz-keyframes fadein {
133 from { opacity: 0; }
134 to { opacity: 1; }
135}
136@keyframes fadein {
137 from { opacity: 0; }
138 to { opacity: 1; }
139}
140@-webkit-keyframes fadeout {
141 from { opacity: 1; }
142 to { opacity: 0; }
143}
144@-moz-keyframes fadeout {
145 from { opacity: 1; }
146 to { opacity: 0; }
147}
148@keyframes fadeout {
149 from { opacity: 1; }
150 to { opacity: 0; }
151}
152.fade.out {
153 opacity: 0;
154 -webkit-animation-duration: 125ms;
155 -webkit-animation-name: fadeout;
156 -moz-animation-duration: 125ms;
157 -moz-animation-name: fadeout;
158 animation-duration: 125ms;
159 animation-name: fadeout;
160}
161.fade.in {
162 opacity: 1;
163 -webkit-animation-duration: 225ms;
164 -webkit-animation-name: fadein;
165 -moz-animation-duration: 225ms;
166 -moz-animation-name: fadein;
167 animation-duration: 225ms;
168 animation-name: fadein;
169}
170.pop {
171 -webkit-transform-origin: 50% 50%;
172 -moz-transform-origin: 50% 50%;
173 transform-origin: 50% 50%;
174}
175.pop.in {
176 -webkit-transform: scale(1);
177 -webkit-animation-name: popin;
178 -webkit-animation-duration: 350ms;
179 -moz-transform: scale(1);
180 -moz-animation-name: popin;
181 -moz-animation-duration: 350ms;
182 transform: scale(1);
183 animation-name: popin;
184 animation-duration: 350ms;
185 opacity: 1;
186}
187.pop.out {
188 -webkit-animation-name: fadeout;
189 -webkit-animation-duration: 100ms;
190 -moz-animation-name: fadeout;
191 -moz-animation-duration: 100ms;
192 animation-name: fadeout;
193 animation-duration: 100ms;
194 opacity: 0;
195}
196.pop.in.reverse {
197 -webkit-animation-name: fadein;
198 -moz-animation-name: fadein;
199 animation-name: fadein;
200}
201.pop.out.reverse {
202 -webkit-transform: scale(.8);
203 -webkit-animation-name: popout;
204 -moz-transform: scale(.8);
205 -moz-animation-name: popout;
206 transform: scale(.8);
207 animation-name: popout;
208}
209@-webkit-keyframes popin {
210 from {
211 -webkit-transform: scale(.8);
212 opacity: 0;
213 }
214 to {
215 -webkit-transform: scale(1);
216 opacity: 1;
217 }
218}
219@-moz-keyframes popin {
220 from {
221 -moz-transform: scale(.8);
222 opacity: 0;
223 }
224 to {
225 -moz-transform: scale(1);
226 opacity: 1;
227 }
228}
229@keyframes popin {
230 from {
231 transform: scale(.8);
232 opacity: 0;
233 }
234 to {
235 transform: scale(1);
236 opacity: 1;
237 }
238}
239@-webkit-keyframes popout {
240 from {
241 -webkit-transform: scale(1);
242 opacity: 1;
243 }
244 to {
245 -webkit-transform: scale(.8);
246 opacity: 0;
247 }
248}
249@-moz-keyframes popout {
250 from {
251 -moz-transform: scale(1);
252 opacity: 1;
253 }
254 to {
255 -moz-transform: scale(.8);
256 opacity: 0;
257 }
258}
259@keyframes popout {
260 from {
261 transform: scale(1);
262 opacity: 1;
263 }
264 to {
265 transform: scale(.8);
266 opacity: 0;
267 }
268}
269/* keyframes for slidein from sides */
270@-webkit-keyframes slideinfromright {
271 from { -webkit-transform: translate3d(100%,0,0); }
272 to { -webkit-transform: translate3d(0,0,0); }
273}
274@-moz-keyframes slideinfromright {
275 from { -moz-transform: translateX(100%); }
276 to { -moz-transform: translateX(0); }
277}
278@keyframes slideinfromright {
279 from { transform: translateX(100%); }
280 to { transform: translateX(0); }
281}
282@-webkit-keyframes slideinfromleft {
283 from { -webkit-transform: translate3d(-100%,0,0); }
284 to { -webkit-transform: translate3d(0,0,0); }
285}
286@-moz-keyframes slideinfromleft {
287 from { -moz-transform: translateX(-100%); }
288 to { -moz-transform: translateX(0); }
289}
290@keyframes slideinfromleft {
291 from { transform: translateX(-100%); }
292 to { transform: translateX(0); }
293}
294/* keyframes for slideout to sides */
295@-webkit-keyframes slideouttoleft {
296 from { -webkit-transform: translate3d(0,0,0); }
297 to { -webkit-transform: translate3d(-100%,0,0); }
298}
299@-moz-keyframes slideouttoleft {
300 from { -moz-transform: translateX(0); }
301 to { -moz-transform: translateX(-100%); }
302}
303@keyframes slideouttoleft {
304 from { transform: translateX(0); }
305 to { transform: translateX(-100%); }
306}
307@-webkit-keyframes slideouttoright {
308 from { -webkit-transform: translate3d(0,0,0); }
309 to { -webkit-transform: translate3d(100%,0,0); }
310}
311@-moz-keyframes slideouttoright {
312 from { -moz-transform: translateX(0); }
313 to { -moz-transform: translateX(100%); }
314}
315@keyframes slideouttoright {
316 from { transform: translateX(0); }
317 to { transform: translateX(100%); }
318}
319.slide.out, .slide.in {
320 -webkit-animation-timing-function: ease-out;
321 -webkit-animation-duration: 350ms;
322 -moz-animation-timing-function: ease-out;
323 -moz-animation-duration: 350ms;
324 animation-timing-function: ease-out;
325 animation-duration: 350ms;
326}
327.slide.out {
328 -webkit-transform: translate3d(-100%,0,0);
329 -webkit-animation-name: slideouttoleft;
330 -moz-transform: translateX(-100%);
331 -moz-animation-name: slideouttoleft;
332 transform: translateX(-100%);
333 animation-name: slideouttoleft;
334}
335.slide.in {
336 -webkit-transform: translate3d(0,0,0);
337 -webkit-animation-name: slideinfromright;
338 -moz-transform: translateX(0);
339 -moz-animation-name: slideinfromright;
340 transform: translateX(0);
341 animation-name: slideinfromright;
342}
343.slide.out.reverse {
344 -webkit-transform: translate3d(100%,0,0);
345 -webkit-animation-name: slideouttoright;
346 -moz-transform: translateX(100%);
347 -moz-animation-name: slideouttoright;
348 transform: translateX(100%);
349 animation-name: slideouttoright;
350}
351.slide.in.reverse {
352 -webkit-transform: translate3d(0,0,0);
353 -webkit-animation-name: slideinfromleft;
354 -moz-transform: translateX(0);
355 -moz-animation-name: slideinfromleft;
356 transform: translateX(0);
357 animation-name: slideinfromleft;
358}
359.slidefade.out {
360 -webkit-transform: translateX(-100%);
361 -webkit-animation-name: slideouttoleft;
362 -webkit-animation-duration: 225ms;
363 -moz-transform: translateX(-100%);
364 -moz-animation-name: slideouttoleft;
365 -moz-animation-duration: 225ms;
366 transform: translateX(-100%);
367 animation-name: slideouttoleft;
368 animation-duration: 225ms;
369}
370.slidefade.in {
371 -webkit-transform: translateX(0);
372 -webkit-animation-name: fadein;
373 -webkit-animation-duration: 200ms;
374 -moz-transform: translateX(0);
375 -moz-animation-name: fadein;
376 -moz-animation-duration: 200ms;
377 transform: translateX(0);
378 animation-name: fadein;
379 animation-duration: 200ms;
380}
381.slidefade.out.reverse {
382 -webkit-transform: translateX(100%);
383 -webkit-animation-name: slideouttoright;
384 -webkit-animation-duration: 200ms;
385 -moz-transform: translateX(100%);
386 -moz-animation-name: slideouttoright;
387 -moz-animation-duration: 200ms;
388 transform: translateX(100%);
389 animation-name: slideouttoright;
390 animation-duration: 200ms;
391}
392.slidefade.in.reverse {
393 -webkit-transform: translateX(0);
394 -webkit-animation-name: fadein;
395 -webkit-animation-duration: 200ms;
396 -moz-transform: translateX(0);
397 -moz-animation-name: fadein;
398 -moz-animation-duration: 200ms;
399 transform: translateX(0);
400 animation-name: fadein;
401 animation-duration: 200ms;
402}
403/* slide down */
404.slidedown.out {
405 -webkit-animation-name: fadeout;
406 -webkit-animation-duration: 100ms;
407 -moz-animation-name: fadeout;
408 -moz-animation-duration: 100ms;
409 animation-name: fadeout;
410 animation-duration: 100ms;
411}
412.slidedown.in {
413 -webkit-transform: translateY(0);
414 -webkit-animation-name: slideinfromtop;
415 -webkit-animation-duration: 250ms;
416 -moz-transform: translateY(0);
417 -moz-animation-name: slideinfromtop;
418 -moz-animation-duration: 250ms;
419 transform: translateY(0);
420 animation-name: slideinfromtop;
421 animation-duration: 250ms;
422}
423.slidedown.in.reverse {
424 -webkit-animation-name: fadein;
425 -webkit-animation-duration: 150ms;
426 -moz-animation-name: fadein;
427 -moz-animation-duration: 150ms;
428 animation-name: fadein;
429 animation-duration: 150ms;
430}
431.slidedown.out.reverse {
432 -webkit-transform: translateY(-100%);
433 -webkit-animation-name: slideouttotop;
434 -webkit-animation-duration: 200ms;
435 -moz-transform: translateY(-100%);
436 -moz-animation-name: slideouttotop;
437 -moz-animation-duration: 200ms;
438 transform: translateY(-100%);
439 animation-name: slideouttotop;
440 animation-duration: 200ms;
441}
442@-webkit-keyframes slideinfromtop {
443 from { -webkit-transform: translateY(-100%); }
444 to { -webkit-transform: translateY(0); }
445}
446@-moz-keyframes slideinfromtop {
447 from { -moz-transform: translateY(-100%); }
448 to { -moz-transform: translateY(0); }
449}
450@keyframes slideinfromtop {
451 from { transform: translateY(-100%); }
452 to { transform: translateY(0); }
453}
454@-webkit-keyframes slideouttotop {
455 from { -webkit-transform: translateY(0); }
456 to { -webkit-transform: translateY(-100%); }
457}
458@-moz-keyframes slideouttotop {
459 from { -moz-transform: translateY(0); }
460 to { -moz-transform: translateY(-100%); }
461}
462@keyframes slideouttotop {
463 from { transform: translateY(0); }
464 to { transform: translateY(-100%); }
465}
466/* slide up */
467.slideup.out {
468 -webkit-animation-name: fadeout;
469 -webkit-animation-duration: 100ms;
470 -moz-animation-name: fadeout;
471 -moz-animation-duration: 100ms;
472 animation-name: fadeout;
473 animation-duration: 100ms;
474}
475.slideup.in {
476 -webkit-transform: translateY(0);
477 -webkit-animation-name: slideinfrombottom;
478 -webkit-animation-duration: 250ms;
479 -moz-transform: translateY(0);
480 -moz-animation-name: slideinfrombottom;
481 -moz-animation-duration: 250ms;
482 transform: translateY(0);
483 animation-name: slideinfrombottom;
484 animation-duration: 250ms;
485}
486.slideup.in.reverse {
487 -webkit-animation-name: fadein;
488 -webkit-animation-duration: 150ms;
489 -moz-animation-name: fadein;
490 -moz-animation-duration: 150ms;
491 animation-name: fadein;
492 animation-duration: 150ms;
493}
494.slideup.out.reverse {
495 -webkit-transform: translateY(100%);
496 -webkit-animation-name: slideouttobottom;
497 -webkit-animation-duration: 200ms;
498 -moz-transform: translateY(100%);
499 -moz-animation-name: slideouttobottom;
500 -moz-animation-duration: 200ms;
501 transform: translateY(100%);
502 animation-name: slideouttobottom;
503 animation-duration: 200ms;
504}
505@-webkit-keyframes slideinfrombottom {
506 from { -webkit-transform: translateY(100%); }
507 to { -webkit-transform: translateY(0); }
508}
509@-moz-keyframes slideinfrombottom {
510 from { -moz-transform: translateY(100%); }
511 to { -moz-transform: translateY(0); }
512}
513@keyframes slideinfrombottom {
514 from { transform: translateY(100%); }
515 to { transform: translateY(0); }
516}
517@-webkit-keyframes slideouttobottom {
518 from { -webkit-transform: translateY(0); }
519 to { -webkit-transform: translateY(100%); }
520}
521@-moz-keyframes slideouttobottom {
522 from { -moz-transform: translateY(0); }
523 to { -moz-transform: translateY(100%); }
524}
525@keyframes slideouttobottom {
526 from { transform: translateY(0); }
527 to { transform: translateY(100%); }
528}
529/* The properties in this rule are only necessary for the 'flip' transition.
530 * We need specify the perspective to create a projection matrix. This will add
531 * some depth as the element flips. The depth number represents the distance of
532 * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
533 * value.
534 */
535.viewport-flip {
536 -webkit-perspective: 1000;
537 -moz-perspective: 1000;
538 perspective: 1000;
539 position: absolute;
540}
541.flip {
542 -webkit-backface-visibility: hidden;
543 -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. */
544 -moz-backface-visibility: hidden;
545 -moz-transform: translateX(0);
546 backface-visibility: hidden;
547 transform: translateX(0);
548}
549.flip.out {
550 -webkit-transform: rotateY(-90deg) scale(.9);
551 -webkit-animation-name: flipouttoleft;
552 -webkit-animation-duration: 175ms;
553 -moz-transform: rotateY(-90deg) scale(.9);
554 -moz-animation-name: flipouttoleft;
555 -moz-animation-duration: 175ms;
556 transform: rotateY(-90deg) scale(.9);
557 animation-name: flipouttoleft;
558 animation-duration: 175ms;
559}
560.flip.in {
561 -webkit-animation-name: flipintoright;
562 -webkit-animation-duration: 225ms;
563 -moz-animation-name: flipintoright;
564 -moz-animation-duration: 225ms;
565 animation-name: flipintoright;
566 animation-duration: 225ms;
567}
568.flip.out.reverse {
569 -webkit-transform: rotateY(90deg) scale(.9);
570 -webkit-animation-name: flipouttoright;
571 -moz-transform: rotateY(90deg) scale(.9);
572 -moz-animation-name: flipouttoright;
573 transform: rotateY(90deg) scale(.9);
574 animation-name: flipouttoright;
575}
576.flip.in.reverse {
577 -webkit-animation-name: flipintoleft;
578 -moz-animation-name: flipintoleft;
579 animation-name: flipintoleft;
580}
581@-webkit-keyframes flipouttoleft {
582 from { -webkit-transform: rotateY(0); }
583 to { -webkit-transform: rotateY(-90deg) scale(.9); }
584}
585@-moz-keyframes flipouttoleft {
586 from { -moz-transform: rotateY(0); }
587 to { -moz-transform: rotateY(-90deg) scale(.9); }
588}
589@keyframes flipouttoleft {
590 from { transform: rotateY(0); }
591 to { transform: rotateY(-90deg) scale(.9); }
592}
593@-webkit-keyframes flipouttoright {
594 from { -webkit-transform: rotateY(0) ; }
595 to { -webkit-transform: rotateY(90deg) scale(.9); }
596}
597@-moz-keyframes flipouttoright {
598 from { -moz-transform: rotateY(0); }
599 to { -moz-transform: rotateY(90deg) scale(.9); }
600}
601@keyframes flipouttoright {
602 from { transform: rotateY(0); }
603 to { transform: rotateY(90deg) scale(.9); }
604}
605@-webkit-keyframes flipintoleft {
606 from { -webkit-transform: rotateY(-90deg) scale(.9); }
607 to { -webkit-transform: rotateY(0); }
608}
609@-moz-keyframes flipintoleft {
610 from { -moz-transform: rotateY(-90deg) scale(.9); }
611 to { -moz-transform: rotateY(0); }
612}
613@keyframes flipintoleft {
614 from { transform: rotateY(-90deg) scale(.9); }
615 to { transform: rotateY(0); }
616}
617@-webkit-keyframes flipintoright {
618 from { -webkit-transform: rotateY(90deg) scale(.9); }
619 to { -webkit-transform: rotateY(0); }
620}
621@-moz-keyframes flipintoright {
622 from { -moz-transform: rotateY(90deg) scale(.9); }
623 to { -moz-transform: rotateY(0); }
624}
625@keyframes flipintoright {
626 from { transform: rotateY(90deg) scale(.9); }
627 to { transform: rotateY(0); }
628}
629/* The properties in this rule are only necessary for the 'flip' transition.
630 * We need specify the perspective to create a projection matrix. This will add
631 * some depth as the element flips. The depth number represents the distance of
632 * the viewer from the z-plane. According to the CSS3 spec, 1000 is a moderate
633 * value.
634 */
635.viewport-turn {
636 -webkit-perspective: 200px;
637 -moz-perspective: 200px;
638 -ms-perspective: 200px;
639 perspective: 200px;
640 position: absolute;
641}
642.turn {
643 -webkit-backface-visibility: hidden;
644 -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. */
645 -webkit-transform-origin: 0;
646
647 -moz-backface-visibility: hidden;
648 -moz-transform: translateX(0);
649 -moz-transform-origin: 0;
650
651 backface-visibility :hidden;
652 transform: translateX(0);
653 transform-origin: 0;
654}
655.turn.out {
656 -webkit-transform: rotateY(-90deg) scale(.9);
657 -webkit-animation-name: flipouttoleft;
658 -webkit-animation-duration: 125ms;
659 -moz-transform: rotateY(-90deg) scale(.9);
660 -moz-animation-name: flipouttoleft;
661 -moz-animation-duration: 125ms;
662 transform: rotateY(-90deg) scale(.9);
663 animation-name: flipouttoleft;
664 animation-duration: 125ms;
665}
666.turn.in {
667 -webkit-animation-name: flipintoright;
668 -webkit-animation-duration: 250ms;
669 -moz-animation-name: flipintoright;
670 -moz-animation-duration: 250ms;
671 animation-name: flipintoright;
672 animation-duration: 250ms;
673
674}
675.turn.out.reverse {
676 -webkit-transform: rotateY(90deg) scale(.9);
677 -webkit-animation-name: flipouttoright;
678 -moz-transform: rotateY(90deg) scale(.9);
679 -moz-animation-name: flipouttoright;
680 transform: rotateY(90deg) scale(.9);
681 animation-name: flipouttoright;
682}
683.turn.in.reverse {
684 -webkit-animation-name: flipintoleft;
685 -moz-animation-name: flipintoleft;
686 animation-name: flipintoleft;
687}
688@-webkit-keyframes flipouttoleft {
689 from { -webkit-transform: rotateY(0); }
690 to { -webkit-transform: rotateY(-90deg) scale(.9); }
691}
692@-moz-keyframes flipouttoleft {
693 from { -moz-transform: rotateY(0); }
694 to { -moz-transform: rotateY(-90deg) scale(.9); }
695}
696@keyframes flipouttoleft {
697 from { transform: rotateY(0); }
698 to { transform: rotateY(-90deg) scale(.9); }
699}
700@-webkit-keyframes flipouttoright {
701 from { -webkit-transform: rotateY(0) ; }
702 to { -webkit-transform: rotateY(90deg) scale(.9); }
703}
704@-moz-keyframes flipouttoright {
705 from { -moz-transform: rotateY(0); }
706 to { -moz-transform: rotateY(90deg) scale(.9); }
707}
708@keyframes flipouttoright {
709 from { transform: rotateY(0); }
710 to { transform: rotateY(90deg) scale(.9); }
711}
712@-webkit-keyframes flipintoleft {
713 from { -webkit-transform: rotateY(-90deg) scale(.9); }
714 to { -webkit-transform: rotateY(0); }
715}
716@-moz-keyframes flipintoleft {
717 from { -moz-transform: rotateY(-90deg) scale(.9); }
718 to { -moz-transform: rotateY(0); }
719}
720@keyframes flipintoleft {
721 from { transform: rotateY(-90deg) scale(.9); }
722 to { transform: rotateY(0); }
723}
724@-webkit-keyframes flipintoright {
725 from { -webkit-transform: rotateY(90deg) scale(.9); }
726 to { -webkit-transform: rotateY(0); }
727}
728@-moz-keyframes flipintoright {
729 from { -moz-transform: rotateY(90deg) scale(.9); }
730 to { -moz-transform: rotateY(0); }
731}
732@keyframes flipintoright {
733 from { transform: rotateY(90deg) scale(.9); }
734 to { transform: rotateY(0); }
735}
736/* flow transition */
737.flow {
738 -webkit-transform-origin: 50% 30%;
739 -webkit-box-shadow: 0 0 20px rgba(0,0,0,.4);
740 -moz-transform-origin: 50% 30%;
741 -moz-box-shadow: 0 0 20px rgba(0,0,0,.4);
742 transform-origin: 50% 30%;
743 box-shadow: 0 0 20px rgba(0,0,0,.4);
744}
745.ui-dialog.flow {
746 -webkit-transform-origin: none;
747 -webkit-box-shadow: none;
748 -moz-transform-origin: none;
749 -moz-box-shadow: none;
750 transform-origin: none;
751 box-shadow: none;
752}
753.flow.out {
754 -webkit-transform: translateX(-100%) scale(.7);
755 -webkit-animation-name: flowouttoleft;
756 -webkit-animation-timing-function: ease;
757 -webkit-animation-duration: 350ms;
758 -moz-transform: translateX(-100%) scale(.7);
759 -moz-animation-name: flowouttoleft;
760 -moz-animation-timing-function: ease;
761 -moz-animation-duration: 350ms;
762 transform: translateX(-100%) scale(.7);
763 animation-name: flowouttoleft;
764 animation-timing-function: ease;
765 animation-duration: 350ms;
766}
767.flow.in {
768 -webkit-transform: translateX(0) scale(1);
769 -webkit-animation-name: flowinfromright;
770 -webkit-animation-timing-function: ease;
771 -webkit-animation-duration: 350ms;
772 -moz-transform: translateX(0) scale(1);
773 -moz-animation-name: flowinfromright;
774 -moz-animation-timing-function: ease;
775 -moz-animation-duration: 350ms;
776 transform: translateX(0) scale(1);
777 animation-name: flowinfromright;
778 animation-timing-function: ease;
779 animation-duration: 350ms;
780}
781.flow.out.reverse {
782 -webkit-transform: translateX(100%);
783 -webkit-animation-name: flowouttoright;
784 -moz-transform: translateX(100%);
785 -moz-animation-name: flowouttoright;
786 transform: translateX(100%);
787 animation-name: flowouttoright;
788}
789.flow.in.reverse {
790 -webkit-animation-name: flowinfromleft;
791 -moz-animation-name: flowinfromleft;
792 animation-name: flowinfromleft;
793}
794@-webkit-keyframes flowouttoleft {
795 0% { -webkit-transform: translateX(0) scale(1); }
796 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
797 100% { -webkit-transform: translateX(-100%) scale(.7); }
798}
799@-moz-keyframes flowouttoleft {
800 0% { -moz-transform: translateX(0) scale(1); }
801 60%, 70% { -moz-transform: translateX(0) scale(.7); }
802 100% { -moz-transform: translateX(-100%) scale(.7); }
803}
804@keyframes flowouttoleft {
805 0% { transform: translateX(0) scale(1); }
806 60%, 70% { transform: translateX(0) scale(.7); }
807 100% { transform: translateX(-100%) scale(.7); }
808}
809@-webkit-keyframes flowouttoright {
810 0% { -webkit-transform: translateX(0) scale(1); }
811 60%, 70% { -webkit-transform: translateX(0) scale(.7); }
812 100% { -webkit-transform: translateX(100%) scale(.7); }
813}
814@-moz-keyframes flowouttoright {
815 0% { -moz-transform: translateX(0) scale(1); }
816 60%, 70% { -moz-transform: translateX(0) scale(.7); }
817 100% { -moz-transform: translateX(100%) scale(.7); }
818}
819@keyframes flowouttoright {
820 0% { transform: translateX(0) scale(1); }
821 60%, 70% { transform: translateX(0) scale(.7); }
822 100% { transform: translateX(100%) scale(.7); }
823}
824@-webkit-keyframes flowinfromleft {
825 0% { -webkit-transform: translateX(-100%) scale(.7); }
826 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
827 100% { -webkit-transform: translateX(0) scale(1); }
828}
829@-moz-keyframes flowinfromleft {
830 0% { -moz-transform: translateX(-100%) scale(.7); }
831 30%, 40% { -moz-transform: translateX(0) scale(.7); }
832 100% { -moz-transform: translateX(0) scale(1); }
833}
834@keyframes flowinfromleft {
835 0% { transform: translateX(-100%) scale(.7); }
836 30%, 40% { transform: translateX(0) scale(.7); }
837 100% { transform: translateX(0) scale(1); }
838}
839@-webkit-keyframes flowinfromright {
840 0% { -webkit-transform: translateX(100%) scale(.7); }
841 30%, 40% { -webkit-transform: translateX(0) scale(.7); }
842 100% { -webkit-transform: translateX(0) scale(1); }
843}
844@-moz-keyframes flowinfromright {
845 0% { -moz-transform: translateX(100%) scale(.7); }
846 30%, 40% { -moz-transform: translateX(0) scale(.7); }
847 100% { -moz-transform: translateX(0) scale(1); }
848}
849@keyframes flowinfromright {
850 0% { transform: translateX(100%) scale(.7); }
851 30%, 40% { transform: translateX(0) scale(.7); }
852 100% { transform: translateX(0) scale(1); }
853}
854/* content configurations. */
855.ui-grid-a, .ui-grid-b, .ui-grid-c, .ui-grid-d { overflow: hidden; }
856.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; }
857/* grid solo: 100 - single item fallback */
858.ui-grid-solo .ui-block-a { display: block; float: none; }
859/* Lower percentages for older browsers (i.e. IE7) to prevent wrapping. -.5px to fix BB5 wrap issue. */
860/* grid a: 50/50 */
861.ui-grid-a .ui-block-a, .ui-grid-a .ui-block-b { width: 49.95%; }
862.ui-grid-a > :nth-child(n) { width: 50%; margin-right: -.5px; }
863.ui-grid-a .ui-block-a { clear: left; }
864/* grid b: 33/33/33 */
865.ui-grid-b .ui-block-a, .ui-grid-b .ui-block-b, .ui-grid-b .ui-block-c { width: 33.25%; }
866.ui-grid-b > :nth-child(n) { width: 33.333%; margin-right: -.5px; }
867.ui-grid-b .ui-block-a { clear: left; }
868/* grid c: 25/25/25/25 */
869.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%; }
870.ui-grid-c > :nth-child(n) { width: 25%; margin-right: -.5px; }
871.ui-grid-c .ui-block-a { clear: left; }
872/* grid d: 20/20/20/20/20 */
873.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%; }
874.ui-grid-d > :nth-child(n) { width: 20%; }
875.ui-grid-d .ui-block-a { clear: left; }
876/* preset breakpoint to switch to stacked grid styles below 35em (560px) */
877@media all and (max-width: 35em) {
878 .ui-responsive .ui-block-a,
879 .ui-responsive .ui-block-b,
880 .ui-responsive .ui-block-c,
881 .ui-responsive .ui-block-d,
882 .ui-responsive .ui-block-e {
883 width: 100%;
884 float:none;
885 }
886}
887/* fixed page header & footer configuration */
888.ui-header-fixed,
889.ui-footer-fixed {
890 left: 0;
891 right: 0;
892 width: 100%;
893 position: fixed;
894 z-index: 1000;
895}
896.ui-header-fixed {
897 top: -1px;
898 padding-top: 1px;
899}
900.ui-header-fixed.ui-fixed-hidden {
901 top: 0;
902 padding-top: 0;
903}
904.ui-footer-fixed {
905 bottom: -1px;
906 padding-bottom: 1px;
907}
908.ui-footer-fixed.ui-fixed-hidden {
909 bottom: 0;
910 padding-bottom: 0;
911}
912.ui-header-fullscreen,
913.ui-footer-fullscreen {
914 filter: Alpha(Opacity=90);
915 opacity: .9;
916}
917.ui-page-header-fixed {
918 padding-top: 2.6875em;
919}
920.ui-page-footer-fixed {
921 padding-bottom: 2.6875em;
922}
923.ui-page-header-fullscreen > .ui-content,
924.ui-page-footer-fullscreen > .ui-content {
925 padding: 0;
926}
927.ui-fixed-hidden {
928 position: absolute;
929}
930.ui-page-header-fullscreen .ui-fixed-hidden,
931.ui-page-footer-fullscreen .ui-fixed-hidden {
932 left: -9999px;
933}
934.ui-header-fixed .ui-btn,
935.ui-footer-fixed .ui-btn {
936 z-index: 10;
937}
938/* workarounds for other widgets */
939.ui-android-2x-fixed .ui-li-has-thumb {
940 -webkit-transform: translate3d(0,0,0);
941}
942.ui-navbar { max-width: 100%; }
943.ui-navbar.ui-mini { margin: 0; }
944.ui-navbar ul:before, .ui-navbar ul:after { content: " "; display: table; }
945.ui-navbar ul:after { clear: both; }
946.ui-navbar ul { list-style:none; margin: 0; padding: 0; position: relative; display: block; border: 0; max-width: 100%; overflow: visible; zoom: 1; }
947.ui-navbar li .ui-btn { display: block; text-align: center; margin: 0 -1px 0 0; border-right-width: 0; }
948.ui-navbar li .ui-btn-icon-right .ui-icon { right: 6px; }
949/* add border if not in header/footer (full width) */
950.ui-navbar li:last-child .ui-btn,
951.ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: 0; border-right-width: 1px; }
952.ui-header .ui-navbar li:last-child .ui-btn,
953.ui-footer .ui-navbar li:last-child .ui-btn,
954.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,
955.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn { margin-right: -1px; border-right-width: 0; }
956.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn { margin-right: -1px; border-right-width: 1px; }
957.ui-header .ui-navbar li .ui-btn,
958.ui-footer .ui-navbar li .ui-btn { border-top-width: 0; border-bottom-width: 0; }
959/* fixing gaps caused by subpixel problem */
960.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,
961.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn { margin-right: -5px; }
962.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
963.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,
964.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,
965.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn { margin-right: -4px; }
966.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
967.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,
968.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
969.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,
970.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,
971.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon { right: 8px; }
972.ui-navbar li .ui-btn .ui-btn-inner { padding-top: .7em; padding-bottom: .8em }
973.ui-navbar li .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
974.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
975.ui-btn { display: block; text-align: center; cursor:pointer; position: relative; margin: .5em 0; padding: 0; }
976.ui-mini { margin-top: .25em; margin-bottom: .25em; }
977.ui-btn-left, .ui-btn-right, .ui-input-clear, .ui-btn-inline,
978.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; margin-left: 5px; }
979.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; }
980.ui-btn input, .ui-btn button { z-index: 2; }
981.ui-btn-left, .ui-btn-right, .ui-btn-inline { display: inline-block; vertical-align: middle; }
982.ui-mobile .ui-btn-left, .ui-mobile .ui-btn-right, .ui-btn-left > .ui-btn, .ui-btn-right > .ui-btn { margin: 0; } /* .ui-mobile to increase specificity level */
983.ui-btn-block { display: block; }
984.ui-header > .ui-btn,
985.ui-footer > .ui-btn { display: inline-block; margin: 0; }
986.ui-header .ui-btn-block,
987.ui-footer .ui-btn-block { display: block; }
988.ui-header .ui-btn-inner,
989.ui-footer .ui-btn-inner,
990.ui-mini .ui-btn-inner { font-size: 12.5px; padding: .55em 11px .5em; }
991.ui-fullsize .ui-btn-inner,
992.ui-fullsize .ui-btn-inner { font-size: 16px; padding: .6em 20px; }
993.ui-btn-icon-notext { width: 24px; height: 24px; }
994.ui-btn-icon-notext .ui-btn-inner { padding: 0; height: 100%; }
995.ui-btn-icon-notext .ui-btn-inner .ui-icon { margin: 2px 1px 2px 3px; float: left; }
996.ui-btn-text { position: relative; z-index: 1; width: 100%; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; }
997div.ui-btn-text { width: auto; }
998.ui-btn-icon-notext .ui-btn-text { position: absolute; left: -9999px; }
999.ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
1000.ui-btn-icon-right .ui-btn-inner { padding-right: 40px; }
1001.ui-btn-icon-top .ui-btn-inner { padding-top: 40px; }
1002.ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 40px; }
1003.ui-header .ui-btn-icon-left .ui-btn-inner,
1004.ui-footer .ui-btn-icon-left .ui-btn-inner,
1005.ui-mini.ui-btn-icon-left .ui-btn-inner,
1006.ui-mini .ui-btn-icon-left .ui-btn-inner { padding-left: 30px; }
1007.ui-header .ui-btn-icon-right .ui-btn-inner,
1008.ui-footer .ui-btn-icon-right .ui-btn-inner,
1009.ui-mini.ui-btn-icon-right .ui-btn-inner,
1010.ui-mini .ui-btn-icon-right .ui-btn-inner { padding-right: 30px; }
1011.ui-header .ui-btn-icon-top .ui-btn-inner,
1012.ui-footer .ui-btn-icon-top .ui-btn-inner { padding: 30px 3px .5em 3px; }
1013.ui-mini.ui-btn-icon-top .ui-btn-inner,
1014.ui-mini .ui-btn-icon-top .ui-btn-inner { padding-top: 30px; }
1015.ui-header .ui-btn-icon-bottom .ui-btn-inner,
1016.ui-footer .ui-btn-icon-bottom .ui-btn-inner { padding: .55em 3px 30px 3px; }
1017.ui-mini.ui-btn-icon-bottom .ui-btn-inner,
1018.ui-mini .ui-btn-icon-bottom .ui-btn-inner { padding-bottom: 30px; }
1019/* Corner styling inheritance */
1020.ui-btn-inner {
1021 -webkit-border-radius: inherit;
1022 border-radius: inherit;
1023}
1024/*btn icon positioning*/
1025.ui-btn-icon-notext .ui-icon { display: block; z-index: 0;}
1026.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; }
1027.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; }
1028.ui-btn-icon-left .ui-icon { left: 10px; }
1029.ui-btn-icon-right .ui-icon { right: 10px; }
1030.ui-btn-icon-top .ui-icon { top: 10px; }
1031.ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
1032.ui-header .ui-btn-icon-left .ui-icon,
1033.ui-footer .ui-btn-icon-left .ui-icon,
1034.ui-mini.ui-btn-icon-left .ui-icon,
1035.ui-mini .ui-btn-icon-left .ui-icon { left: 5px; }
1036.ui-header .ui-btn-icon-right .ui-icon,
1037.ui-footer .ui-btn-icon-right .ui-icon,
1038.ui-mini.ui-btn-icon-right .ui-icon,
1039.ui-mini .ui-btn-icon-right .ui-icon { right: 5px; }
1040.ui-header .ui-btn-icon-top .ui-icon,
1041.ui-footer .ui-btn-icon-top .ui-icon,
1042.ui-mini.ui-btn-icon-top .ui-icon,
1043.ui-mini .ui-btn-icon-top .ui-icon { top: 5px; }
1044.ui-header .ui-btn-icon-bottom .ui-icon,
1045.ui-footer .ui-btn-icon-bottom .ui-icon,
1046.ui-mini.ui-btn-icon-bottom .ui-icon,
1047.ui-mini .ui-btn-icon-bottom .ui-icon { bottom: 5px; }
1048/*hiding native button,inputs */
1049.ui-btn-hidden { position: absolute; top: 0; left: 0; width: 100%; height: 100%; -webkit-appearance: none; cursor: pointer; background: #fff; background: rgba(255,255,255,0); filter: Alpha(Opacity=0); opacity: .1; font-size: 1px; border: none; text-indent: -9999px; }
1050/* Fixes IE/WP filter alpha opacity bugs */
1051.ui-disabled .ui-btn-hidden { display: none; }
1052.ui-disabled { z-index: 1; }
1053.ui-field-contain .ui-btn.ui-submit { margin: 0; }
1054label.ui-submit { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
1055@media all and (min-width: 28em){
1056 .ui-field-contain label.ui-submit { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
1057 .ui-field-contain .ui-btn.ui-submit { width: 78%; display: inline-block; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
1058 .ui-hide-label .ui-btn.ui-submit { width: auto; display: block; }
1059}
1060.ui-collapsible-inset { margin: .5em 0; }
1061.ui-collapsible-heading { font-size: 16px; display: block; margin: 0 -15px; padding: 0; position: relative; }
1062.ui-collapsible-inset .ui-collapsible-heading { margin: 0; }
1063.ui-collapsible-heading .ui-btn { text-align: left; margin: 0; border-left-width: 0; border-right-width: 0; }
1064.ui-collapsible-inset .ui-collapsible-heading .ui-btn { border-right-width: 1px; border-left-width: 1px; }
1065.ui-collapsible-collapsed + .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn { border-top-width: 0; }
1066.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn { border-top-width: 1px; }
1067.ui-collapsible-heading .ui-btn-inner { padding-left: 12px; padding-right: 12px; }
1068.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner { padding-left: 40px; }
1069.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner { padding-right: 40px; }
1070.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,
1071.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner { text-align: center; }
1072.ui-collapsible-heading .ui-btn-icon-left.ui-mini .ui-btn-inner { padding-left: 30px; }
1073.ui-collapsible-heading .ui-btn-icon-right.ui-mini .ui-btn-inner { padding-right: 30px; }
1074.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 0 1px 2px; text-indent: -9999px; }
1075.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner { padding: 10px 0; }
1076.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon { left: 0; margin-top: -10px; }
1077.ui-collapsible-heading-status { position: absolute; top: -9999px; left: 0; }
1078.ui-collapsible-content {
1079 display: block;
1080 margin: 0 -15px;
1081 padding: 10px 15px;
1082 border-left-width: 0;
1083 border-right-width: 0;
1084 border-top: none; /* Overrides ui-body-* */
1085 background-image: none; /* Overrides ui-body-* */
1086}
1087.ui-collapsible-inset .ui-collapsible-content { margin: 0; border-right-width: 1px; border-left-width: 1px; }
1088.ui-collapsible-content-collapsed { display: none; }
1089.ui-collapsible-set > .ui-collapsible.ui-corner-all {
1090 -webkit-border-radius: 0;
1091 border-radius: 0;
1092}
1093.ui-collapsible-heading,
1094.ui-collapsible-heading > .ui-btn {
1095 -webkit-border-radius: inherit;
1096 border-radius: inherit;
1097}
1098.ui-collapsible-set .ui-collapsible.ui-first-child {
1099 -webkit-border-top-right-radius: inherit;
1100 border-top-right-radius: inherit;
1101 -webkit-border-top-left-radius: inherit;
1102 border-top-left-radius: inherit;
1103}
1104.ui-collapsible-content,
1105.ui-collapsible-set .ui-collapsible.ui-last-child {
1106 -webkit-border-bottom-right-radius: inherit;
1107 border-bottom-right-radius: inherit;
1108 -webkit-border-bottom-left-radius: inherit;
1109 border-bottom-left-radius: inherit;
1110}
1111.ui-collapsible-themed-content:not(.ui-collapsible-collapsed) > .ui-collapsible-heading {
1112 -webkit-border-bottom-right-radius: 0;
1113 border-bottom-right-radius: 0;
1114 -webkit-border-bottom-left-radius: 0;
1115 border-bottom-left-radius: 0;
1116}
1117.ui-collapsible-set { margin: .5em 0; }
1118.ui-collapsible-set .ui-collapsible { margin: -1px 0 0; }
1119.ui-collapsible-set .ui-collapsible.ui-first-child { margin-top: 0; }
1120.ui-controlgroup, fieldset.ui-controlgroup { padding: 0; margin: .5em 0; zoom: 1; }
1121.ui-controlgroup.ui-mini, fieldset.ui-controlgroup.ui-mini { margin: .25em 0; }
1122.ui-field-contain .ui-controlgroup, .ui-field-contain fieldset.ui-controlgroup { margin: 0; }
1123.ui-bar .ui-controlgroup { margin: 0 5px; }
1124.ui-controlgroup-label { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .4em; }
1125/* Fixes legend not wrapping on IE10 */
1126.ui-controlgroup-label legend { max-width: 100%; }
1127.ui-controlgroup-controls label.ui-select,
1128.ui-controlgroup-controls label.ui-submit { position: absolute; left: -9999px; }
1129.ui-controlgroup li { list-style: none; }
1130.ui-controlgroup .ui-btn { margin: 0; }
1131.ui-controlgroup .ui-btn-icon-notext { width: auto; height: auto; top: auto; }
1132.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { height: 20px; padding: .6em 20px .6em 20px }
1133.ui-controlgroup-horizontal .ui-btn-icon-notext .ui-btn-inner { width: 18px; }
1134.ui-controlgroup.ui-mini .ui-btn-icon-notext .ui-btn-inner,
1135.ui-header .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner,
1136.ui-footer .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner { height: 16px; padding: .55em 11px .5em 11px; }
1137.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; right: 50%; margin: -9px -9px 0 0; }
1138.ui-controlgroup-horizontal .ui-btn-inner { text-align: center; }
1139.ui-controlgroup-horizontal.ui-mini .ui-btn-inner { height: 16px; line-height: 16px; }
1140.ui-controlgroup .ui-checkbox label, .ui-controlgroup .ui-radio label { font-size: 16px; }
1141.ui-controlgroup-horizontal .ui-controlgroup-controls:before,
1142.ui-controlgroup-horizontal .ui-controlgroup-controls:after { content: ""; display: table; }
1143.ui-controlgroup-horizontal .ui-controlgroup-controls:after { clear: both; }
1144.ui-controlgroup-horizontal .ui-controlgroup-controls { display: inline-block; vertical-align: middle; zoom: 1; }
1145.ui-controlgroup-horizontal .ui-controlgroup-controls > .ui-btn, .ui-controlgroup-horizontal .ui-controlgroup-controls li > .ui-btn,
1146.ui-controlgroup-horizontal .ui-checkbox, .ui-controlgroup-horizontal .ui-radio,
1147.ui-controlgroup-horizontal .ui-select { float: left; clear: none; margin: 0; }
1148/* On IE7 the floating selects will be displayed as block if .ui-btn-text has width 100% */
1149.ui-controlgroup-horizontal .ui-select .ui-btn-text { width: auto; }
1150.ui-controlgroup-vertical .ui-btn { border-bottom-width: 0; }
1151.ui-controlgroup-vertical .ui-btn.ui-last-child { border-bottom-width: 1px; }
1152.ui-controlgroup-horizontal .ui-btn { border-right-width: 0; }
1153.ui-controlgroup-horizontal .ui-btn.ui-last-child { border-right-width: 1px; }
1154.ui-controlgroup .ui-btn-corner-all {
1155 -webkit-border-radius: 0;
1156 border-radius: 0;
1157}
1158.ui-controlgroup .ui-controlgroup-controls,
1159.ui-controlgroup .ui-radio,
1160.ui-controlgroup .ui-checkbox,
1161.ui-controlgroup .ui-select,
1162.ui-controlgroup li {
1163 -webkit-border-radius: inherit;
1164 border-radius: inherit;
1165}
1166.ui-controlgroup-vertical .ui-btn.ui-first-child {
1167 -webkit-border-top-left-radius: inherit;
1168 border-top-left-radius: inherit;
1169 -webkit-border-top-right-radius: inherit;
1170 border-top-right-radius: inherit;
1171}
1172.ui-controlgroup-vertical .ui-btn.ui-last-child {
1173 -webkit-border-bottom-left-radius: inherit;
1174 border-bottom-left-radius: inherit;
1175 -webkit-border-bottom-right-radius: inherit;
1176 border-bottom-right-radius: inherit;
1177}
1178.ui-controlgroup-horizontal .ui-btn.ui-first-child {
1179 -webkit-border-top-left-radius: inherit;
1180 border-top-left-radius: inherit;
1181 -webkit-border-bottom-left-radius: inherit;
1182 border-bottom-left-radius: inherit;
1183}
1184.ui-controlgroup-horizontal .ui-btn.ui-last-child {
1185 -webkit-border-top-right-radius: inherit;
1186 border-top-right-radius: inherit;
1187 -webkit-border-bottom-right-radius: inherit;
1188 border-bottom-right-radius: inherit;
1189}
1190.ui-controlgroup .ui-shadow:not(.ui-focus) {
1191 -moz-box-shadow: none;
1192 -webkit-box-shadow: none;
1193 box-shadow: none;
1194}
1195@media all and (min-width: 28em){
1196 .ui-field-contain .ui-controlgroup-label { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
1197 .ui-field-contain .ui-controlgroup-controls { width: 78%; display: inline-block; }
1198 .ui-field-contain .ui-controlgroup .ui-select { width: 100%; display: block; }
1199 .ui-field-contain .ui-controlgroup-horizontal .ui-select { width: auto; }
1200 .ui-hide-label .ui-controlgroup-controls { width: 100%; }
1201}
1202.ui-dialog {
1203 background: none !important; /* this is to ensure that dialog theming does not apply (by default at least) on the page div */
1204}
1205.ui-dialog-contain {
1206 width: 92.5%;
1207 max-width: 500px;
1208 margin: 10% auto 15px auto;
1209 padding: 0;
1210 position: relative;
1211 top: -15px;
1212}
1213.ui-dialog-contain > .ui-header,
1214.ui-dialog-contain > .ui-content,
1215.ui-dialog-contain > .ui-footer {
1216 display: block;
1217 position: relative;
1218 width: auto;
1219 margin: 0;
1220}
1221.ui-dialog-contain > .ui-header {
1222 border: none;
1223 overflow: hidden;
1224 z-index: 10;
1225 padding: 0;
1226}
1227.ui-dialog-contain > .ui-content {
1228 padding: 15px;
1229}
1230.ui-dialog-contain > .ui-footer {
1231 z-index: 10;
1232 padding: 0 15px;
1233}
1234.ui-popup-open .ui-header-fixed,
1235.ui-popup-open .ui-footer-fixed {
1236 position: absolute !important; /* See line #553 of popup.js */
1237}
1238.ui-popup-screen {
1239 background-image: url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==); /* Necessary to set some form of background to ensure element is clickable in IE6/7. While legacy IE won't understand the data-URI'd image, it ensures no additional requests occur in all other browsers with little overhead. */
1240 top: 0;
1241 left: 0;
1242 right: 0;
1243 bottom: 1px;
1244 position: absolute;
1245 filter: Alpha(Opacity=0);
1246 opacity: 0;
1247 z-index: 1099;
1248}
1249.ui-popup-screen.in {
1250 opacity: 0.5;
1251 filter: Alpha(Opacity=50);
1252}
1253.ui-popup-screen.out {
1254 opacity: 0;
1255 filter: Alpha(Opacity=0);
1256}
1257.ui-popup-container {
1258 z-index: 1100;
1259 display: inline-block;
1260 position: absolute;
1261 padding: 0;
1262 outline: 0;
1263}
1264.ui-popup {
1265 position: relative;
1266}
1267.ui-popup.ui-content,
1268.ui-popup .ui-content {
1269 overflow: visible;
1270}
1271.ui-popup > p,
1272.ui-popup > h1,
1273.ui-popup > h2,
1274.ui-popup > h3,
1275.ui-popup > h4,
1276.ui-popup > h5,
1277.ui-popup > h6 {
1278 margin: .5em 7px;
1279}
1280.ui-popup > span {
1281 display: block;
1282 margin: .5em 7px;
1283}
1284.ui-popup .ui-title {
1285 font-size: 16px;
1286 font-weight: bold;
1287 margin-top: .5em;
1288 margin-bottom: .5em;
1289}
1290.ui-popup-container .ui-content > p,
1291.ui-popup-container .ui-content > h1,
1292.ui-popup-container .ui-content > h2,
1293.ui-popup-container .ui-content > h3,
1294.ui-popup-container .ui-content > h4,
1295.ui-popup-container .ui-content > h5,
1296.ui-popup-container .ui-content > h6 {
1297 margin: .5em 0;
1298}
1299.ui-popup-container .ui-content > span {
1300 margin: 0;
1301}
1302.ui-popup-container .ui-content > p:first-child,
1303.ui-popup-container .ui-content > h1:first-child,
1304.ui-popup-container .ui-content > h2:first-child,
1305.ui-popup-container .ui-content > h3:first-child,
1306.ui-popup-container .ui-content > h4:first-child,
1307.ui-popup-container .ui-content > h5:first-child,
1308.ui-popup-container .ui-content > h6:first-child {
1309 margin-top: 0;
1310}
1311.ui-popup-container .ui-content > p:last-child,
1312.ui-popup-container .ui-content > h1:last-child,
1313.ui-popup-container .ui-content > h2:last-child,
1314.ui-popup-container .ui-content > h3:last-child,
1315.ui-popup-container .ui-content > h4:last-child,
1316.ui-popup-container .ui-content > h5:last-child,
1317.ui-popup-container .ui-content > h6:last-child {
1318 margin-bottom: 0;
1319}
1320.ui-popup > img {
1321 width: auto;
1322 height: auto;
1323 max-width: 100%;
1324 max-height: 100%;
1325 vertical-align: middle;
1326}
1327.ui-popup:not(.ui-content) > img:only-child,
1328.ui-popup:not(.ui-content) > .ui-btn-left:first-child + img:last-child,
1329.ui-popup:not(.ui-content) > .ui-btn-right:first-child + img:last-child {
1330 -webkit-border-radius: inherit;
1331 border-radius: inherit;
1332}
1333.ui-popup iframe {
1334 vertical-align: middle;
1335}
1336@media all and (min-width: 28em){
1337 .ui-popup .ui-field-contain label.ui-submit,
1338 .ui-popup .ui-field-contain .ui-controlgroup-label,
1339 .ui-popup .ui-field-contain label.ui-select,
1340 .ui-popup .ui-field-contain label.ui-input-text {
1341 font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em;
1342 }
1343 .ui-popup .ui-field-contain .ui-btn.ui-submit,
1344 .ui-popup .ui-field-contain .ui-controlgroup-controls,
1345 .ui-popup .ui-field-contain .ui-select,
1346 .ui-popup .ui-field-contain input.ui-input-text,
1347 .ui-popup .ui-field-contain textarea.ui-input-text,
1348 .ui-popup .ui-field-contain .ui-input-search {
1349 width: 100%; display: block;
1350 }
1351}
1352.ui-popup > .ui-btn-left,
1353.ui-popup > .ui-btn-right {
1354 position: absolute;
1355 top: -9px;
1356 margin: 0;
1357 z-index: 1101;
1358}
1359.ui-popup > .ui-btn-left { left: -9px; }
1360.ui-popup > .ui-btn-right { right: -9px; }
1361.ui-popup-hidden { top: -99999px; left: -9999px; visibility: hidden; }
1362.ui-checkbox, .ui-radio { position: relative; clear: both; margin: 0; z-index: 1; }
1363.ui-checkbox .ui-btn, .ui-radio .ui-btn { text-align: left; z-index: 2; }
1364.ui-controlgroup .ui-checkbox .ui-btn, .ui-controlgroup .ui-radio .ui-btn { margin: 0; }
1365.ui-checkbox .ui-btn-inner, .ui-radio .ui-btn-inner { white-space: normal; }
1366.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner { padding-left: 45px; }
1367.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; }
1368.ui-checkbox .ui-btn-icon-right .ui-btn-inner, .ui-radio .ui-btn-icon-right .ui-btn-inner { padding-right: 45px; }
1369.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; }
1370.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; }
1371.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; }
1372.ui-checkbox .ui-icon, .ui-radio .ui-icon { top: 1.1em; }
1373.ui-checkbox .ui-btn-icon-left .ui-icon, .ui-radio .ui-btn-icon-left .ui-icon { left: 15px; }
1374.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon, .ui-radio .ui-mini.ui-btn-icon-left .ui-icon { left: 9px; }
1375.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
1376.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
1377.ui-checkbox .ui-btn-icon-top .ui-icon, .ui-radio .ui-btn-icon-top .ui-icon { top: 10px; }
1378.ui-checkbox .ui-btn-icon-bottom .ui-icon, .ui-radio .ui-btn-icon-bottom .ui-icon { top: auto; bottom: 10px; }
1379.ui-checkbox .ui-btn-icon-right .ui-icon, .ui-radio .ui-btn-icon-right .ui-icon { right: 15px; }
1380.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon, .ui-radio .ui-mini.ui-btn-icon-right .ui-icon { right: 9px; }
1381.ui-controlgroup-horizontal .ui-checkbox .ui-icon,
1382.ui-controlgroup-horizontal .ui-radio .ui-icon { display: none; }
1383.ui-controlgroup-horizontal .ui-checkbox .ui-btn-inner,
1384.ui-controlgroup-horizontal .ui-radio .ui-btn-inner { padding: .6em 20px; }
1385.ui-controlgroup-horizontal .ui-checkbox .ui-mini .ui-btn-inner,
1386.ui-controlgroup-horizontal .ui-radio .ui-mini .ui-btn-inner { padding: .55em 11px .5em; }
1387/* input, label positioning */
1388.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; }
1389.ui-field-contain, fieldset.ui-field-contain { padding: .8em 0; margin: 0; border-width: 0 0 1px 0; overflow: visible; }
1390.ui-field-contain:last-child { border-bottom-width: 0; }
1391.ui-field-contain { max-width: 100%; } /* This prevents horizontal scrollbar in IE7 */
1392@media all and (min-width: 28em){
1393 .ui-field-contain, .ui-mobile fieldset.ui-field-contain { border-width: 0; padding: 0; margin: 1em 0; }
1394}
1395.ui-select { display: block; position: relative; }
1396.ui-select select { position: absolute; left: -9999px; top: -9999px; }
1397.ui-select .ui-btn { opacity: 1; }
1398.ui-field-contain .ui-select .ui-btn { margin: 0; }
1399/* 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. */
1400.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%; filter: Alpha(Opacity=0); opacity: 0; z-index: 2; }
1401.ui-select .ui-disabled { opacity: .3; }
1402/* Display none because of issues with IE/WP's filter alpha opacity */
1403.ui-select .ui-disabled select { display: none; }
1404@-moz-document url-prefix() { .ui-select .ui-btn select { opacity: 0.0001; }}
1405.ui-select .ui-btn.ui-select-nativeonly { border-radius: 0; border: 0; }
1406.ui-select .ui-btn.ui-select-nativeonly select { opacity: 1; text-indent: 0; display: block; }
1407.ui-select .ui-disabled.ui-select-nativeonly .ui-btn-inner { opacity: 0; }
1408.ui-select .ui-btn-icon-right .ui-btn-inner, .ui-select .ui-li-has-count .ui-btn-inner { padding-right: 45px; }
1409.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner { padding-right: 32px; }
1410.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 80px; }
1411.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner { padding-right: 67px; }
1412.ui-select .ui-btn-icon-right .ui-icon { right: 15px; }
1413.ui-select .ui-mini.ui-btn-icon-right .ui-icon { right: 7px; }
1414.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 45px; }
1415.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count { right: 32px; }
1416/* labels */
1417label.ui-select { font-size: 16px; line-height: 1.4; font-weight: normal; margin: 0 0 .3em; display: block; }
1418/*listbox*/
1419.ui-select .ui-btn-text, .ui-selectmenu .ui-btn-text { display: block; min-height: 1em; overflow: hidden !important;
1420/* This !important is required for iPad Safari specifically. See https://github.com/jquery/jquery-mobile/issues/2647 */ }
1421.ui-select .ui-btn-text { text-overflow: ellipsis; }
1422.ui-selectmenu { padding: 6px; min-width: 160px; }
1423.ui-selectmenu .ui-listview { margin: 0; }
1424.ui-selectmenu .ui-btn.ui-li-divider { cursor: default; }
1425.ui-screen-hidden, .ui-selectmenu-list .ui-li .ui-icon { display: none; }
1426.ui-selectmenu-list .ui-li .ui-icon { display: block; }
1427.ui-li.ui-selectmenu-placeholder { display: none; }
1428.ui-selectmenu .ui-header { margin: 0; padding: 0; }
1429.ui-selectmenu.ui-popup .ui-header { -webkit-border-top-left-radius: 0; border-top-left-radius: 0; -webkit-border-top-right-radius: 0; border-top-right-radius: 0; }
1430.ui-selectmenu .ui-header .ui-title { margin: 0.6em 46px 0.8em; }
1431@media all and (min-width: 28em){
1432 .ui-field-contain label.ui-select { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0; }
1433 .ui-field-contain .ui-select { width: 78%; display: inline-block; }
1434 .ui-hide-label .ui-select { width: 100%; }
1435}
1436/* 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 */
1437.ui-selectmenu .ui-header h1:after { content: '.'; visibility: hidden; }
1438label.ui-input-text { font-size: 16px; line-height: 1.4; display: block; font-weight: normal; margin: 0 0 .3em; }
1439input.ui-input-text, textarea.ui-input-text { background-image: none; padding: .4em; margin: .5em 0; min-height: 1.4em; line-height: 1.4em; font-size: 16px; display: block; width: 100%; outline: 0; }
1440input.ui-mini, .ui-mini input, textarea.ui-mini { font-size: 14px; }
1441div.ui-input-text input.ui-input-text, div.ui-input-text textarea.ui-input-text,
1442.ui-input-search input.ui-input-text { border: none; width: 100%; padding: .4em 0; margin: 0; display: block; background: transparent none; outline: 0 !important; }
1443.ui-input-search, div.ui-input-text { margin: .5em 0; background-image: none; position: relative; }
1444.ui-input-search { padding: 0 30px; }
1445div.ui-input-text { padding: 0 .4em; }
1446div.ui-input-has-clear { padding: 0 30px 0 .4em; }
1447input.ui-input-text.ui-mini, textarea.ui-input-text.ui-mini,
1448.ui-input-search.ui-mini, div.ui-input-text.ui-mini { margin: .25em 0; }
1449.ui-field-contain input.ui-input-text, .ui-field-contain textarea.ui-input-text,
1450.ui-field-contain .ui-input-search, .ui-field-contain div.ui-input-text { margin: 0; }
1451textarea.ui-input-text { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
1452input.ui-input-text { -webkit-appearance: none; }
1453textarea.ui-input-text { height: 50px; -webkit-transition: height 200ms linear; -moz-transition: height 200ms linear; -o-transition: height 200ms linear; transition: height 200ms linear; }
1454textarea.ui-mini { height: 45px; }
1455.ui-icon-searchfield:after { position: absolute; left: 7px; top: 50%; margin-top: -9px; content: ""; width: 18px; height: 18px; opacity: .5; }
1456.ui-input-search .ui-input-clear, .ui-input-text .ui-input-clear { position: absolute; right: 0; top: 50%; margin-top: -13px; }
1457.ui-mini .ui-input-clear { right: -3px; }
1458.ui-input-search .ui-input-clear-hidden, .ui-input-text .ui-input-clear-hidden { display: none; }
1459/* Resolves issue #5166: Added to support issue introduced in Firefox 15. We can likely remove this in the future. */
1460input::-moz-placeholder, textarea::-moz-placeholder { color: #aaa; }
1461/* For IE10 */
1462:-ms-input-placeholder { color: #aaa; }
1463/* Resolves issue #5131: Width of textinput depends on its type, for Android 4.1 */
1464input[type=number]::-webkit-outer-spin-button { margin: 0; }
1465@media all and (min-width: 28em){
1466 .ui-field-contain label.ui-input-text { vertical-align: top; display: inline-block; width: 20%; margin: 0 2% 0 0 }
1467 .ui-field-contain input.ui-input-text,
1468 .ui-field-contain textarea.ui-input-text,
1469 .ui-field-contain .ui-input-search,
1470 .ui-field-contain div.ui-input-text { width: 78%; display: inline-block; }
1471 .ui-field-contain .ui-input-search,
1472 .ui-field-contain div.ui-input-text { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; }
1473 .ui-hide-label input.ui-input-text,
1474 .ui-hide-label textarea.ui-input-text,
1475 .ui-hide-label .ui-input-search,
1476 .ui-hide-label div.ui-input-text,
1477 .ui-input-search input.ui-input-text,
1478 div.ui-input-text input.ui-input-text { width: 100%; }
1479}
1480.ui-rangeslider {
1481 zoom: 1;
1482 margin: 0;
1483}
1484.ui-rangeslider:before,
1485.ui-rangeslider:after {
1486 content: "";
1487 display: table;
1488}
1489.ui-rangeslider:after {
1490 clear: both;
1491}
1492/* Margin-top/bottom: .5em * 16px/14px to make it equal to ui-rangeslider-sliders margin (input font-size is 14px) */
1493.ui-rangeslider input.ui-input-text.ui-slider-input {
1494 margin: .57143em 0;
1495}
1496.ui-rangeslider.ui-mini input.ui-slider-input {
1497 margin: .28571em 0;
1498}
1499.ui-rangeslider input.ui-slider-input.ui-rangeslider-last {
1500 float: right;
1501}
1502.ui-rangeslider .ui-rangeslider-sliders {
1503 position: relative;
1504 overflow: visible;
1505 height: 30px;
1506 margin: .5em 68px;
1507}
1508.ui-rangeslider.ui-mini .ui-rangeslider-sliders {
1509 margin: .25em 68px;
1510}
1511.ui-field-contain .ui-rangeslider input.ui-slider-input,
1512.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input,
1513.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,
1514.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
1515 margin-top: 0;
1516 margin-bottom: 0;
1517}
1518.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track {
1519 position: absolute;
1520 top: 6px;
1521 right: 0;
1522 left: 0;
1523 margin: 0;
1524}
1525.ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track {
1526 top: 8px;
1527}
1528.ui-rangeslider .ui-slider-track:first-child .ui-slider-bg {
1529 display: none;
1530}
1531.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child {
1532 background-color: transparent;
1533 background: none;
1534 border-width: 0;
1535 height: 0;
1536}
1537/* this makes ie6 and ie7 set height to 0 to fix z-index problem */
1538html >/**/body .ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child {
1539 height: 15px;
1540 border-width: 1px;
1541}
1542html >/**/body .ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track:first-child {
1543 height: 12px;
1544}
1545@media all and (min-width: 28em){
1546 .ui-field-contain .ui-rangeslider label.ui-slider {
1547 float: left;
1548 }
1549 .ui-field-contain .ui-rangeslider input.ui-slider-input {
1550 position: relative;
1551 z-index: 1;
1552 }
1553 .ui-field-contain .ui-rangeslider input.ui-slider-input.ui-rangeslider-first,
1554 .ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input.ui-rangeslider-first {
1555 margin-right: 17px;
1556 }
1557 .ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,
1558 .ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
1559 float: left;
1560 width: 78%;
1561 margin: 0 -68px;
1562 }
1563 .ui-field-contain .ui-rangeslider .ui-slider-track,
1564 .ui-field-contain .ui-rangeslider.ui-mini .ui-slider-track {
1565 right: 68px;
1566 left: 68px;
1567 }
1568 .ui-field-contain.ui-hide-label .ui-rangeslider input.ui-slider-input.ui-rangeslider-first {
1569 margin: 0;
1570 }
1571 .ui-field-contain.ui-hide-label .ui-rangeslider .ui-rangeslider-sliders,
1572 .ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-rangeslider-sliders {
1573 width: auto;
1574 float: none;
1575 margin: 0 68px;
1576 }
1577 .ui-field-contain.ui-hide-label .ui-rangeslider .ui-slider-track,
1578 .ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-slider-track {
1579 right: 0;
1580 left: 0;
1581 }
1582}
1583.ui-listview { margin: 0; }
1584ol.ui-listview, ol.ui-listview .ui-li-divider { counter-reset: listnumbering; }
1585.ui-content .ui-listview, .ui-panel-inner > .ui-listview { margin: -15px; }
1586.ui-collapsible-content > .ui-listview { margin: -10px -15px; }
1587.ui-content .ui-listview-inset, .ui-panel-inner .ui-listview-inset { margin: 1em 0; }
1588.ui-collapsible-content .ui-listview-inset { margin: .5em 0; }
1589.ui-listview, .ui-li { list-style: none; padding: 0; }
1590.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; }
1591.ui-li.ui-btn, .ui-li.ui-field-contain, .ui-li-divider, .ui-li-static { margin: 0; }
1592.ui-listview-inset .ui-li { border-right-width: 1px; border-left-width: 1px; }
1593.ui-li.ui-last-child, .ui-li.ui-field-contain.ui-last-child { border-bottom-width: 1px; }
1594.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) > .ui-li.ui-first-child { border-top-width: 0; }
1595.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset) > .ui-li.ui-last-child { border-bottom-width: 0; }
1596.ui-li .ui-btn-text a.ui-link-inherit { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
1597.ui-li-static { background-image: none; }
1598.ui-li-divider { padding: .5em 15px; font-size: 14px; font-weight: bold; }
1599ol.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) ". "; }
1600ol.ui-listview .ui-li-jsnumbering:before { content: "" !important; } /* to avoid chance of duplication */
1601.ui-listview .ui-li > .ui-btn-text {
1602 -webkit-border-radius: inherit;
1603 border-radius: inherit;
1604}
1605.ui-listview > .ui-li.ui-first-child,
1606.ui-listview .ui-btn.ui-first-child > .ui-li > .ui-btn-text > .ui-link-inherit {
1607 -webkit-border-top-right-radius: inherit;
1608 border-top-right-radius: inherit;
1609 -webkit-border-top-left-radius: inherit;
1610 border-top-left-radius: inherit;
1611}
1612.ui-listview > .ui-li.ui-last-child,
1613.ui-listview .ui-btn.ui-last-child > .ui-li > .ui-btn-text > .ui-link-inherit,
1614.ui-collapsible-content > .ui-listview:not(.ui-listview-inset),
1615.ui-collapsible-content > .ui-listview:not(.ui-listview-inset) .ui-li.ui-last-child {
1616 -webkit-border-bottom-right-radius: inherit;
1617 border-bottom-right-radius: inherit;
1618 -webkit-border-bottom-left-radius: inherit;
1619 border-bottom-left-radius: inherit;
1620}
1621.ui-listview > .ui-li.ui-first-child .ui-li-link-alt {
1622 -webkit-border-top-right-radius: inherit;
1623 border-top-right-radius: inherit;
1624}
1625.ui-listview > .ui-li.ui-last-child .ui-li-link-alt {
1626 -webkit-border-bottom-right-radius: inherit;
1627 border-bottom-right-radius: inherit;
1628}
1629.ui-listview > .ui-li.ui-first-child .ui-li-thumb:not(.ui-li-icon) {
1630 -webkit-border-top-left-radius: inherit;
1631 border-top-left-radius: inherit;
1632}
1633.ui-listview > .ui-li.ui-last-child .ui-li-thumb:not(.ui-li-icon) {
1634 -webkit-border-bottom-left-radius: inherit;
1635 border-bottom-left-radius: inherit;
1636}
1637.ui-li>.ui-btn-inner { display: block; position: relative; padding: 0; }
1638.ui-li .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li { padding: .7em 15px; display: block; }
1639.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-thumb { min-height: 59px; padding-left: 100px; }
1640.ui-li-has-icon .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-icon { min-height: 20px; padding-left: 40px; }
1641.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; }
1642.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-arrow { padding-right: 40px; }
1643.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; }
1644.ui-li-heading { font-size: 16px; font-weight: bold; display: block; margin: .6em 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
1645.ui-li-desc { font-size: 12px; font-weight: normal; display: block; margin: -.5em 0 .6em; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }
1646ol.ui-listview > .ui-li .ui-li-heading { display: inline-block; width: 100%; margin-left: -1.3em; text-indent: 1.3em; vertical-align: middle; }
1647ol.ui-listview > .ui-li .ui-li-desc:not(.ui-li-aside) { text-indent: 1.55em; }
1648.ui-li-thumb, .ui-listview .ui-li-icon { position: absolute; left: 1px; top: 0; max-height: 80px; max-width: 80px; }
1649.ui-listview .ui-li-icon { max-height: 16px; max-width: 16px; left: 10px; top: .9em; }
1650.ui-li-thumb, .ui-listview .ui-li-icon, .ui-li-content { float: left; margin-right: 10px; }
1651.ui-li-aside { float: right; width: 50%; text-align: right; margin: .3em 0; }
1652@media all and (min-width: 480px){
1653 .ui-li-aside { width: 45%; }
1654}
1655.ui-li-divider { cursor: default; }
1656.ui-li-has-alt .ui-btn-inner a.ui-link-inherit, .ui-li-static.ui-li-has-alt { padding-right: 53px; }
1657.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; }
1658.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; }
1659.ui-li-has-count.ui-li-divider .ui-li-count, .ui-li-has-count .ui-link-inherit .ui-li-count { margin-top: -.95em; }
1660.ui-li-has-arrow.ui-li-has-count .ui-li-count { right: 40px; }
1661.ui-li-has-alt.ui-li-has-count .ui-li-count { right: 53px; }
1662.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; }
1663.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;}
1664.ui-li-link-alt .ui-btn-inner { padding: 0; height: 100%; position: absolute; width: 100%; top: 0; left: 0;}
1665.ui-li-link-alt .ui-btn .ui-icon { right: 50%; margin-right: -9px; }
1666.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon { position: absolute; top: 50%; margin-top: -9px; }
1667.ui-listview * .ui-btn-inner > .ui-btn > .ui-btn-inner { border-top: 0; }
1668.ui-listview-filter { border-width: 0; overflow: hidden; margin: -15px -15px 15px -15px; }
1669.ui-collapsible-content .ui-listview-filter { margin: -10px -15px 10px -15px; border-bottom: inherit; }
1670.ui-listview-filter-inset { margin: -15px -5px; background: transparent; }
1671.ui-collapsible-content .ui-listview-filter-inset { margin: -5px; border-bottom-width: 0; }
1672.ui-listview-filter .ui-input-search { margin: 5px; width: auto; display: block; }
1673.ui-li.ui-screen-hidden{ display:none; }
1674/* Odd iPad positioning issue. */
1675@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
1676 .ui-li .ui-btn-text { overflow: visible; }
1677}
1678label.ui-slider {
1679 font-size: 16px;
1680 line-height: 1.4;
1681 font-weight: normal;
1682 margin: 0;
1683 display: block;
1684}
1685.ui-field-contain label.ui-slider {
1686 margin-bottom: .4em;
1687}
1688div.ui-slider {
1689 height: 30px;
1690 margin: .5em 0;
1691 zoom: 1;
1692}
1693div.ui-slider.ui-mini {
1694 margin: .25em 0;
1695}
1696.ui-field-contain div.ui-slider,
1697.ui-field-contain div.ui-slider.ui-mini {
1698 margin: 0;
1699}
1700div.ui-slider:before, div.ui-slider:after {
1701 content: "";
1702 display: table;
1703}
1704div.ui-slider:after {
1705 clear: both;
1706}
1707/* High level of specificity to override Textinput CSS. */
1708input.ui-input-text.ui-slider-input {
1709 display: block;
1710 float: left;
1711 margin: 0;
1712 padding: 4px;
1713 width: 40px;
1714 height: 22px;
1715 line-height: 22px;
1716 font-size: 14px;
1717 border-width: 0;
1718 background-image: none;
1719 font-weight: bold;
1720 text-align: center;
1721 vertical-align: text-bottom;
1722 outline: 0;
1723 -webkit-box-sizing: content-box;
1724 -moz-box-sizing: content-box;
1725 -ms-box-sizing: content-box;
1726 box-sizing: content-box;
1727}
1728.ui-slider-input::-webkit-outer-spin-button,
1729.ui-slider-input::-webkit-inner-spin-button {
1730 -webkit-appearance: none;
1731 margin: 0;
1732}
1733.ui-slider-track,
1734.ui-slider-switch {
1735 position: relative;
1736 overflow: visible;
1737 height: 15px;
1738 margin: 0 15px 0 68px;
1739 top: 6px;
1740}
1741.ui-slider-track.ui-mini {
1742 height: 12px;
1743 top: 8px;
1744}
1745.ui-slider-bg {
1746 border: none;
1747 height: 100%;
1748}
1749/* High level of specificity to override button margins in grids */
1750.ui-slider-track .ui-btn.ui-slider-handle,
1751.ui-slider-switch .ui-btn.ui-slider-handle {
1752 position: absolute;
1753 z-index: 1;
1754 top: 50%;
1755 width: 28px;
1756 height: 28px;
1757 margin: -15px 0 0 -15px;
1758 outline: 0;
1759}
1760.ui-slider-track.ui-mini .ui-slider-handle {
1761 height: 14px;
1762 width: 14px;
1763 margin: -8px 0 0 -7px;
1764}
1765.ui-slider-handle .ui-btn-inner {
1766 padding: 0;
1767 height: 100%;
1768}
1769.ui-slider-track.ui-mini .ui-slider-handle .ui-btn-inner {
1770 height: 30px;
1771 width: 30px;
1772 padding: 0;
1773 margin: -9px 0 0 -9px;
1774 border-top: none;
1775}
1776select.ui-slider-switch {
1777 display: none;
1778}
1779div.ui-slider-switch {
1780 display: inline-block;
1781 height: 32px;
1782 width: 5.8em;
1783 margin: .5em 0;
1784 top: 0;
1785}
1786/* reset the clearfix */
1787div.ui-slider-switch:before, div.ui-slider-switch:after {
1788 display: none;
1789 clear: none;
1790}
1791div.ui-slider-switch.ui-mini {
1792 width: 5em;
1793 height: 29px;
1794 margin: .25em 0;
1795 top: 0;
1796}
1797.ui-field-contain .ui-slider-switch,
1798.ui-field-contain .ui-slider-switch.ui-mini {
1799 margin: 0;
1800}
1801.ui-slider-inneroffset {
1802 margin: 0 16px;
1803 position: relative;
1804 z-index: 1;
1805}
1806.ui-slider-switch.ui-mini .ui-slider-inneroffset {
1807 margin: 0 15px 0 14px;
1808}
1809.ui-slider-switch .ui-btn.ui-slider-handle {
1810 margin: 1px 0 0 -15px;
1811}
1812.ui-slider-switch.ui-mini .ui-slider-handle {
1813 width: 25px;
1814 height: 25px;
1815 margin: 1px 0 0 -13px;
1816 padding: 0;
1817}
1818.ui-slider-handle-snapping {
1819 -webkit-transition: left 70ms linear;
1820 -moz-transition: left 70ms linear;
1821}
1822.ui-slider-switch.ui-mini .ui-slider-handle .ui-btn-inner {
1823 height: 30px;
1824 width: 30px;
1825 padding: 0;
1826 margin: 0;
1827 border-top: none;
1828}
1829.ui-slider-switch .ui-slider-label {
1830 position: absolute;
1831 text-align: center;
1832 width: 100%;
1833 overflow: hidden;
1834 font-size: 16px;
1835 top: 0;
1836 line-height: 2;
1837 min-height: 100%;
1838 border-width: 0;
1839 white-space: nowrap;
1840 cursor: pointer;
1841}
1842.ui-slider-switch.ui-mini .ui-slider-label {
1843 font-size: 14px;
1844}
1845.ui-slider-switch .ui-slider-label-a {
1846 z-index: 1;
1847 left: 0;
1848 text-indent: -1.5em;
1849}
1850.ui-slider-switch .ui-slider-label-b {
1851 z-index: 0;
1852 right: 0;
1853 text-indent: 1.5em;
1854}
1855@media all and (min-width: 28em){
1856 .ui-field-contain label.ui-slider {
1857 vertical-align: top;
1858 display: inline-block;
1859 width: 20%;
1860 margin: 0 2% 0 0;
1861 }
1862 .ui-field-contain div.ui-slider {
1863 display: inline-block;
1864 width: 78%;
1865 }
1866 .ui-field-contain.ui-hide-label div.ui-slider {
1867 display: block;
1868 width: auto;
1869 }
1870 .ui-field-contain div.ui-slider-switch,
1871 .ui-field-contain.ui-hide-label div.ui-slider-switch {
1872 display: inline-block;
1873 width: 5.8em;
1874 }
1875 .ui-field-contain div.ui-slider-switch.ui-mini {
1876 width: 5em;
1877 }
1878}
1879.ui-table {
1880 border: 0;
1881 border-collapse: collapse;
1882 padding: 0;
1883 width: 100%;
1884}
1885.ui-table th,
1886.ui-table td {
1887 line-height: 1.5em;
1888 text-align: left;
1889 padding: .4em .5em;
1890 vertical-align:top;
1891}
1892.ui-table th .ui-btn,
1893.ui-table td .ui-btn {
1894 line-height: normal;
1895}
1896.ui-table th {
1897 font-weight: bold;
1898}
1899.ui-table caption {
1900 text-align:left;
1901 margin-bottom:1.4em;
1902 opacity: .5;
1903}
1904/* Add strokes between each row */
1905.table-stroke thead th {
1906 border-bottom: 1px solid #d6d6d6; /* non-RGBA fallback */
1907 border-bottom: 1px solid rgba(0, 0, 0, .1);
1908}
1909.table-stroke tbody th,
1910.table-stroke tbody td {
1911 border-bottom: 1px solid #e6e6e6; /* non-RGBA fallback */
1912 border-bottom: 1px solid rgba(0, 0, 0, .05);
1913}
1914/* Add alternating row stripes */
1915.table-stripe tbody tr:nth-child(odd) td,
1916.table-stripe tbody tr:nth-child(odd) th {
1917 background-color: #eeeeee; /* non-RGBA fallback */
1918 background-color: rgba(0,0,0,0.04);
1919}
1920/* Add stroke to the header and last item */
1921.table-stripe thead th,
1922.table-stripe tbody tr:last-child {
1923 border-bottom: 1px solid #d6d6d6; /* non-RGBA fallback */
1924 border-bottom: 1px solid rgba(0, 0, 0, .1);
1925}
1926/*
1927 Styles for the table columntoggle mode
1928*/
1929.ui-table-columntoggle-btn {
1930 float: right;
1931 margin-bottom:.8em;
1932}
1933/* Remove top/bottom margins around the fieldcontain on check list */
1934.ui-table-columntoggle-popup fieldset {
1935 margin:0;
1936}
1937/* Hide all prioritized columns by default */
1938@media only all {
1939 th.ui-table-priority-6,
1940 td.ui-table-priority-6,
1941 th.ui-table-priority-5,
1942 td.ui-table-priority-5,
1943 th.ui-table-priority-4,
1944 td.ui-table-priority-4,
1945 th.ui-table-priority-3,
1946 td.ui-table-priority-3,
1947 th.ui-table-priority-2,
1948 td.ui-table-priority-2,
1949 th.ui-table-priority-1,
1950 td.ui-table-priority-1 {
1951 display: none;
1952 }
1953}
1954/* Preset breakpoints if ".ui-responsive" class added to table */
1955/* Show priority 1 at 320px (20em x 16px) */
1956@media screen and (min-width: 20em) {
1957 .ui-table-columntoggle.ui-responsive th.ui-table-priority-1,
1958 .ui-table-columntoggle.ui-responsive td.ui-table-priority-1 {
1959 display: table-cell;
1960 }
1961}
1962/* Show priority 2 at 480px (30em x 16px) */
1963@media screen and (min-width: 30em) {
1964 .ui-table-columntoggle.ui-responsive th.ui-table-priority-2,
1965 .ui-table-columntoggle.ui-responsive td.ui-table-priority-2 {
1966 display: table-cell;
1967 }
1968}
1969/* Show priority 3 at 640px (40em x 16px) */
1970@media screen and (min-width: 40em) {
1971 .ui-table-columntoggle.ui-responsive th.ui-table-priority-3,
1972 .ui-table-columntoggle.ui-responsive td.ui-table-priority-3 {
1973 display: table-cell;
1974 }
1975}
1976/* Show priority 4 at 800px (50em x 16px) */
1977@media screen and (min-width: 50em) {
1978 .ui-table-columntoggle.ui-responsive th.ui-table-priority-4,
1979 .ui-table-columntoggle.ui-responsive td.ui-table-priority-4 {
1980 display: table-cell;
1981 }
1982}
1983/* Show priority 5 at 960px (60em x 16px) */
1984@media screen and (min-width: 60em) {
1985 .ui-table-columntoggle.ui-responsive th.ui-table-priority-5,
1986 .ui-table-columntoggle.ui-responsive td.ui-table-priority-5 {
1987 display: table-cell;
1988 }
1989}
1990/* Show priority 6 at 1,120px (70em x 16px) */
1991@media screen and (min-width: 70em) {
1992 .ui-table-columntoggle.ui-responsive th.ui-table-priority-6,
1993 .ui-table-columntoggle.ui-responsive td.ui-table-priority-6 {
1994 display: table-cell;
1995 }
1996}
1997/* Unchecked manually: Always hide */
1998.ui-table-columntoggle th.ui-table-cell-hidden,
1999.ui-table-columntoggle td.ui-table-cell-hidden,
2000.ui-table-columntoggle.ui-responsive th.ui-table-cell-hidden,
2001.ui-table-columntoggle.ui-responsive td.ui-table-cell-hidden {
2002 display: none;
2003}
2004/* Checked manually: Always show */
2005.ui-table-columntoggle th.ui-table-cell-visible,
2006.ui-table-columntoggle td.ui-table-cell-visible,
2007.ui-table-columntoggle.ui-responsive th.ui-table-cell-visible,
2008.ui-table-columntoggle.ui-responsive td.ui-table-cell-visible {
2009 display: table-cell;
2010}
2011/*
2012 Styles for the table columntoggle mode
2013*/
2014.ui-table-reflow td .ui-table-cell-label,
2015.ui-table-reflow th .ui-table-cell-label {
2016 display: none;
2017}
2018/* Mobile first styles: Begin with the stacked presentation at narrow widths */
2019@media only all {
2020 /* Hide the table headers */
2021 .ui-table-reflow thead td,
2022 .ui-table-reflow thead th {
2023 display: none;
2024 }
2025 /* Show the table cells as a block level element */
2026 .ui-table-reflow td,
2027 .ui-table-reflow th {
2028 text-align: left;
2029 display: block;
2030 }
2031 /* Add a fair amount of top margin to visually separate each row when stacked */
2032 .ui-table-reflow tbody th {
2033 margin-top: 3em;
2034 }
2035 /* Make the label elements a percentage width */
2036 .ui-table-reflow td .ui-table-cell-label,
2037 .ui-table-reflow th .ui-table-cell-label {
2038 padding: .4em;
2039 min-width: 30%;
2040 display: inline-block;
2041 margin: -.4em 1em -.4em -.4em;
2042 }
2043 /* For grouped headers, have a different style to visually separate the levels by classing the first label in each col group */
2044 .ui-table-reflow th .ui-table-cell-label-top,
2045 .ui-table-reflow td .ui-table-cell-label-top {
2046 display: block;
2047 padding: .4em 0;
2048 margin: .4em 0;
2049 text-transform: uppercase;
2050 font-size: .9em;
2051 font-weight: normal;
2052 }
2053}
2054/* Breakpoint to show as a standard table at 560px (35em x 16px) or wider */
2055@media ( min-width: 35em ) {
2056 /* Fixes table rendering when switching between breakpoints in Safari <= 5. See https://github.com/jquery/jquery-mobile/issues/5380 */
2057 .ui-table-reflow.ui-responsive {
2058 display: table-row-group;
2059 }
2060 /* Show the table header rows */
2061 .ui-table-reflow.ui-responsive td,
2062 .ui-table-reflow.ui-responsive th,
2063 .ui-table-reflow.ui-responsive tbody th,
2064 .ui-table-reflow.ui-responsive tbody td,
2065 .ui-table-reflow.ui-responsive thead td,
2066 .ui-table-reflow.ui-responsive thead th {
2067 display: table-cell;
2068 margin: 0;
2069 }
2070 /* Hide the labels in each cell */
2071 .ui-table-reflow.ui-responsive td .ui-table-cell-label,
2072 .ui-table-reflow.ui-responsive th .ui-table-cell-label {
2073 display: none;
2074 }
2075}
2076/* Hack to make IE9 and WP7.5 treat cells like block level elements, scoped to ui-responsive class */
2077/* Applied in a max-width media query up to the table layout breakpoint so we don't need to negate this*/
2078@media ( max-width: 35em ) {
2079 .ui-table-reflow.ui-responsive td,
2080 .ui-table-reflow.ui-responsive th {
2081 width: 100%;
2082 -webkit-box-sizing: border-box;
2083 -moz-box-sizing: border-box;
2084 box-sizing: border-box;
2085 float: left;
2086 clear: left;
2087 }
2088}
2089/* panel */
2090.ui-panel {
2091 width: 17em;
2092 min-height: 100%;
2093 max-height: none;
2094 border-width: 0;
2095 position: absolute;
2096 top: 0;
2097 display: block;
2098}
2099.ui-panel-closed {
2100 width: 0;
2101 max-height: 100%;
2102 overflow: hidden;
2103 visibility: hidden;
2104}
2105.ui-panel-fixed {
2106 position: fixed;
2107 bottom: -1px; /* fixes gap on Chrome for Android */
2108 padding-bottom: 1px;
2109}
2110.ui-panel-display-overlay {
2111 z-index: 1001; /* fixed toolbars have z-index 1000 */
2112}
2113.ui-panel-display-reveal {
2114 z-index: 0;
2115}
2116.ui-panel-display-push {
2117 z-index: 999;
2118}
2119.ui-panel-inner {
2120 padding: 15px;
2121}
2122/* content-wrap */
2123.ui-panel-content-wrap {
2124 position: relative;
2125 left: 0;
2126 min-height: inherit;
2127 border: none;
2128 z-index: 999;
2129}
2130.ui-panel-content-wrap-display-overlay,
2131.ui-panel-animate.ui-panel-content-wrap > .ui-header, /* ios4 fix */
2132.ui-panel-content-wrap-closed {
2133 position: static;
2134}
2135/* dismiss */
2136.ui-panel-dismiss {
2137 position: absolute;
2138 top: 0;
2139 left:0;
2140 height: 100%;
2141 width: 100%;
2142 z-index: 1002;
2143 display: none;
2144}
2145.ui-panel-dismiss-open {
2146 display: block;
2147}
2148/* animate class is added to panel, wrapper and fixed toolbars */
2149.ui-panel-animate {
2150 -webkit-transition: -webkit-transform 350ms ease;
2151 -moz-transition: -moz-transform 350ms ease;
2152 transition: transform 350ms ease;
2153}
2154/* hardware acceleration for smoother transitions on WebKit browsers */
2155.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal),
2156.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal) > div,
2157.ui-panel-animate.ui-panel-closed.ui-panel-display-reveal > div,
2158.ui-panel-animate.ui-panel-content-wrap,
2159.ui-panel-animate.ui-panel-content-fixed-toolbar {
2160 -webkit-backface-visibility: hidden;
2161 -webkit-transform: translate3d(0,0,0);
2162}
2163/* positioning: panel */
2164/* panel left */
2165.ui-panel-position-left {
2166 left: -17em;
2167}
2168/* animated: panel left (for overlay and push) */
2169.ui-panel-animate.ui-panel-position-left.ui-panel-display-overlay,
2170.ui-panel-animate.ui-panel-position-left.ui-panel-display-push {
2171 left: 0;
2172 -webkit-transform: translate3d(-17em,0,0);
2173 -moz-transform: translate3d(-17em,0,0);
2174 transform: translate3d(-17em,0,0);
2175}
2176/* panel left open */
2177.ui-panel-position-left.ui-panel-display-reveal, /* negate "panel left" for reveal */
2178.ui-panel-position-left.ui-panel-open {
2179 left: 0;
2180}
2181/* animated: panel left open (for overlay and push) */
2182.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-overlay,
2183.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-push {
2184 -webkit-transform: translate3d(0,0,0);
2185 transform: translate3d(0,0,0);
2186 -moz-transform: none;
2187}
2188/* panel right */
2189.ui-panel-position-right {
2190 right: -17em;
2191}
2192/* animated: panel right (for overlay and push) */
2193.ui-panel-animate.ui-panel-position-right.ui-panel-display-overlay,
2194.ui-panel-animate.ui-panel-position-right.ui-panel-display-push {
2195 right: 0;
2196 -webkit-transform: translate3d(17em,0,0);
2197 -moz-transform: translate3d(17em,0,0);
2198 transform: translate3d(17em,0,0);
2199}
2200/* panel right open */
2201.ui-panel-position-right.ui-panel-display-reveal, /* negate "panel right" for reveal */
2202.ui-panel-position-right.ui-panel-open {
2203 right: 0;
2204}
2205/* animated: panel right open (for overlay and push) */
2206.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-overlay,
2207.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-push {
2208 -webkit-transform: translate3d(0,0,0);
2209 transform: translate3d(0,0,0);
2210 -moz-transform: none;
2211}
2212/* positioning: content wrap, fixed toolbars and dismiss */
2213/* panel left open */
2214.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open,
2215.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open,
2216.ui-panel-dismiss-position-left.ui-panel-dismiss-open {
2217 left: 17em;
2218 right: -17em;
2219}
2220/* animated: panel left open (for reveal and push) */
2221.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,
2222.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,
2223.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,
2224.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push {
2225 left: 0;
2226 right: 0;
2227 -webkit-transform: translate3d(17em,0,0);
2228 -moz-transform: translate3d(17em,0,0);
2229 transform: translate3d(17em,0,0);
2230}
2231/* panel right open */
2232.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open,
2233.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open,
2234.ui-panel-dismiss-position-right.ui-panel-dismiss-open {
2235 left: -17em;
2236 right: 17em;
2237}
2238/* animated: panel right open (for reveal and push) */
2239.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,
2240.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,
2241.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,
2242.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push {
2243 left: 0;
2244 right: 0;
2245 -webkit-transform: translate3d(-17em,0,0);
2246 -moz-transform: translate3d(-17em,0,0);
2247 transform: translate3d(-17em,0,0);
2248}
2249/* negate "panel left/right open" for overlay */
2250.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-overlay,
2251.ui-panel-content-wrap-open.ui-panel-content-wrap-display-overlay {
2252 left: 0;
2253}
2254/* always disable overflow-x to prevent zoom issue on Android */
2255.ui-page-active.ui-page-panel {
2256 overflow-x: hidden;
2257}
2258/* shadows and borders */
2259.ui-panel-display-reveal {
2260 -webkit-box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
2261 -moz-box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
2262 box-shadow: inset -5px 0 5px rgba(0,0,0,.15);
2263}
2264.ui-panel-position-right.ui-panel-display-reveal {
2265 -webkit-box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
2266 -moz-box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
2267 box-shadow: inset 5px 0 5px rgba(0,0,0,.15);
2268}
2269.ui-panel-display-overlay {
2270 -webkit-box-shadow: 5px 0 5px rgba(0,0,0,.15);
2271 -moz-box-shadow: 5px 0 5px rgba(0,0,0,.15);
2272 box-shadow: 5px 0 5px rgba(0,0,0,.15);
2273}
2274.ui-panel-position-right.ui-panel-display-overlay {
2275 -webkit-box-shadow: -5px 0 5px rgba(0,0,0,.15);
2276 -moz-box-shadow: -5px 0 5px rgba(0,0,0,.15);
2277 box-shadow: -5px 0 5px rgba(0,0,0,.15);
2278}
2279.ui-panel-display-push.ui-panel-open.ui-panel-position-left {
2280 border-right-width: 1px;
2281 margin-right: -1px;
2282}
2283.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push {
2284 margin-left: 1px;
2285}
2286.ui-panel-display-push.ui-panel-open.ui-panel-position-right {
2287 border-left-width: 1px;
2288 margin-left: -1px;
2289}
2290.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push {
2291 margin-right: 1px;
2292}
2293/* wrap on wide viewports once open */
2294@media (min-width:55em){
2295 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-left,
2296 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-left,
2297 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-left,
2298 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-left {
2299 margin-right: 17em;
2300 }
2301 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-right,
2302 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-right,
2303 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-right,
2304 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-right {
2305 margin-left: 17em;
2306 }
2307 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push,
2308 .ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal {
2309 width: auto;
2310 }
2311 .ui-responsive-panel .ui-panel-dismiss-display-push {
2312 display: none;
2313 }
2314}
diff --git a/static/vendor/jquery.mobile.theme-1.3.2.css b/static/vendor/jquery.mobile.theme-1.3.2.css
deleted file mode 100644
index f87f6b1..0000000
--- a/static/vendor/jquery.mobile.theme-1.3.2.css
+++ /dev/null
@@ -1,1068 +0,0 @@
1/*!
2* jQuery Mobile 1.3.2
3* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
4* http://jquerymobile.com
5*
6* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
7* Released under the MIT license.
8* http://jquery.org/license
9*
10*/
11
12
13/* Swatches */
14/* A
15-----------------------------------------------------------------------------------------------------------*/
16.ui-bar-a {
17 border: 1px solid #333 /*{a-bar-border}*/;
18 background: #111 /*{a-bar-background-color}*/;
19 color: #fff /*{a-bar-color}*/;
20 font-weight: bold;
21 text-shadow: 0 /*{a-bar-shadow-x}*/ -1px /*{a-bar-shadow-y}*/ 0 /*{a-bar-shadow-radius}*/ #000 /*{a-bar-shadow-color}*/;
22 background-image: -webkit-gradient(linear, left top, left bottom, from( #3c3c3c /*{a-bar-background-start}*/), to( #111 /*{a-bar-background-end}*/)); /* Saf4+, Chrome */
23 background-image: -webkit-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
24 background-image: -moz-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* FF3.6 */
25 background-image: -ms-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* IE10 */
26 background-image: -o-linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/); /* Opera 11.10+ */
27 background-image: linear-gradient( #3c3c3c /*{a-bar-background-start}*/, #111 /*{a-bar-background-end}*/);
28}
29.ui-bar-a,
30.ui-bar-a input,
31.ui-bar-a select,
32.ui-bar-a textarea,
33.ui-bar-a button {
34 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
35}
36.ui-bar-a .ui-link-inherit {
37 color: #fff /*{a-bar-color}*/;
38}
39.ui-bar-a a.ui-link {
40 color: #7cc4e7 /*{a-bar-link-color}*/;
41 font-weight: bold;
42}
43.ui-bar-a a.ui-link:visited {
44 color: #2489ce /*{a-bar-link-visited}*/;
45}
46.ui-bar-a a.ui-link:hover {
47 color: #2489ce /*{a-bar-link-hover}*/;
48}
49.ui-bar-a a.ui-link:active {
50 color: #2489ce /*{a-bar-link-active}*/;
51}
52.ui-body-a,
53.ui-overlay-a {
54 border: 1px solid #444 /*{a-body-border}*/;
55 background: #222 /*{a-body-background-color}*/;
56 color: #fff /*{a-body-color}*/;
57 text-shadow: 0 /*{a-body-shadow-x}*/ 1px /*{a-body-shadow-y}*/ 0 /*{a-body-shadow-radius}*/ #111 /*{a-body-shadow-color}*/;
58 font-weight: normal;
59 background-image: -webkit-gradient(linear, left top, left bottom, from( #444 /*{a-body-background-start}*/), to( #222 /*{a-body-background-end}*/)); /* Saf4+, Chrome */
60 background-image: -webkit-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
61 background-image: -moz-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* FF3.6 */
62 background-image: -ms-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* IE10 */
63 background-image: -o-linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/); /* Opera 11.10+ */
64 background-image: linear-gradient( #444 /*{a-body-background-start}*/, #222 /*{a-body-background-end}*/);
65}
66.ui-overlay-a {
67 background-image: none;
68 border-width: 0;
69}
70.ui-body-a,
71.ui-body-a input,
72.ui-body-a select,
73.ui-body-a textarea,
74.ui-body-a button {
75 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
76}
77.ui-body-a .ui-link-inherit {
78 color: #fff /*{a-body-color}*/;
79}
80.ui-body-a .ui-link {
81 color: #2489ce /*{a-body-link-color}*/;
82 font-weight: bold;
83}
84.ui-body-a .ui-link:visited {
85 color: #2489ce /*{a-body-link-visited}*/;
86}
87.ui-body-a .ui-link:hover {
88 color: #2489ce /*{a-body-link-hover}*/;
89}
90.ui-body-a .ui-link:active {
91 color: #2489ce /*{a-body-link-active}*/;
92}
93.ui-btn-up-a {
94 border: 1px solid #111 /*{a-bup-border}*/;
95 background: #333 /*{a-bup-background-color}*/;
96 font-weight: bold;
97 color: #fff /*{a-bup-color}*/;
98 text-shadow: 0 /*{a-bup-shadow-x}*/ 1px /*{a-bup-shadow-y}*/ 0 /*{a-bup-shadow-radius}*/ #111 /*{a-bup-shadow-color}*/;
99 background-image: -webkit-gradient(linear, left top, left bottom, from( #444 /*{a-bup-background-start}*/), to( #2d2d2d /*{a-bup-background-end}*/)); /* Saf4+, Chrome */
100 background-image: -webkit-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
101 background-image: -moz-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* FF3.6 */
102 background-image: -ms-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* IE10 */
103 background-image: -o-linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/); /* Opera 11.10+ */
104 background-image: linear-gradient( #444 /*{a-bup-background-start}*/, #2d2d2d /*{a-bup-background-end}*/);
105}
106.ui-btn-up-a:visited,
107.ui-btn-up-a a.ui-link-inherit {
108 color: #fff /*{a-bup-color}*/;
109}
110.ui-btn-hover-a {
111 border: 1px solid #000 /*{a-bhover-border}*/;
112 background: #444 /*{a-bhover-background-color}*/;
113 font-weight: bold;
114 color: #fff /*{a-bhover-color}*/;
115 text-shadow: 0 /*{a-bhover-shadow-x}*/ 1px /*{a-bhover-shadow-y}*/ 0 /*{a-bhover-shadow-radius}*/ #111 /*{a-bhover-shadow-color}*/;
116 background-image: -webkit-gradient(linear, left top, left bottom, from( #555 /*{a-bhover-background-start}*/), to( #383838 /*{a-bhover-background-end}*/)); /* Saf4+, Chrome */
117 background-image: -webkit-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
118 background-image: -moz-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* FF3.6 */
119 background-image: -ms-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* IE10 */
120 background-image: -o-linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/); /* Opera 11.10+ */
121 background-image: linear-gradient( #555 /*{a-bhover-background-start}*/, #383838 /*{a-bhover-background-end}*/);
122}
123.ui-btn-hover-a:visited,
124.ui-btn-hover-a:hover,
125.ui-btn-hover-a a.ui-link-inherit {
126 color: #fff /*{a-bhover-color}*/;
127}
128.ui-btn-down-a {
129 border: 1px solid #000 /*{a-bdown-border}*/;
130 background: #222 /*{a-bdown-background-color}*/;
131 font-weight: bold;
132 color: #fff /*{a-bdown-color}*/;
133 text-shadow: 0 /*{a-bdown-shadow-x}*/ 1px /*{a-bdown-shadow-y}*/ 0 /*{a-bdown-shadow-radius}*/ #111 /*{a-bdown-shadow-color}*/;
134 background-image: -webkit-gradient(linear, left top, left bottom, from( #202020 /*{a-bdown-background-start}*/), to( #2c2c2c /*{a-bdown-background-end}*/)); /* Saf4+, Chrome */
135 background-image: -webkit-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
136 background-image: -moz-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* FF3.6 */
137 background-image: -ms-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* IE10 */
138 background-image: -o-linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/); /* Opera 11.10+ */
139 background-image: linear-gradient( #202020 /*{a-bdown-background-start}*/, #2c2c2c /*{a-bdown-background-end}*/);
140}
141.ui-btn-down-a:visited,
142.ui-btn-down-a:hover,
143.ui-btn-down-a a.ui-link-inherit {
144 color: #fff /*{a-bdown-color}*/;
145}
146.ui-btn-up-a,
147.ui-btn-hover-a,
148.ui-btn-down-a {
149 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
150 text-decoration: none;
151}
152/* B
153-----------------------------------------------------------------------------------------------------------*/
154.ui-bar-b {
155 border: 1px solid #456f9a /*{b-bar-border}*/;
156 background: #5e87b0 /*{b-bar-background-color}*/;
157 color: #fff /*{b-bar-color}*/;
158 font-weight: bold;
159 text-shadow: 0 /*{b-bar-shadow-x}*/ 1px /*{b-bar-shadow-y}*/ 0 /*{b-bar-shadow-radius}*/ #3e6790 /*{b-bar-shadow-color}*/;
160 background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bar-background-start}*/), to( #497bae /*{b-bar-background-end}*/)); /* Saf4+, Chrome */
161 background-image: -webkit-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
162 background-image: -moz-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* FF3.6 */
163 background-image: -ms-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* IE10 */
164 background-image: -o-linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/); /* Opera 11.10+ */
165 background-image: linear-gradient( #6facd5 /*{b-bar-background-start}*/, #497bae /*{b-bar-background-end}*/);
166}
167.ui-bar-b,
168.ui-bar-b input,
169.ui-bar-b select,
170.ui-bar-b textarea,
171.ui-bar-b button {
172 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
173}
174.ui-bar-b .ui-link-inherit {
175 color: #fff /*{b-bar-color}*/;
176}
177.ui-bar-b a.ui-link {
178 color: #ddf0f8 /*{b-bar-link-color}*/;
179 font-weight: bold;
180}
181.ui-bar-b a.ui-link:visited {
182 color: #ddf0f8 /*{b-bar-link-visited}*/;
183}
184.ui-bar-b a.ui-link:hover {
185 color: #ddf0f8 /*{b-bar-link-hover}*/;
186}
187.ui-bar-b a.ui-link:active {
188 color: #ddf0f8 /*{b-bar-link-active}*/;
189}
190.ui-body-b,
191.ui-overlay-b {
192 border: 1px solid #999 /*{b-body-border}*/;
193 background: #f3f3f3 /*{b-body-background-color}*/;
194 color: #222 /*{b-body-color}*/;
195 text-shadow: 0 /*{b-body-shadow-x}*/ 1px /*{b-body-shadow-y}*/ 0 /*{b-body-shadow-radius}*/ #fff /*{b-body-shadow-color}*/;
196 font-weight: normal;
197 background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{b-body-background-start}*/), to( #ccc /*{b-body-background-end}*/)); /* Saf4+, Chrome */
198 background-image: -webkit-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
199 background-image: -moz-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* FF3.6 */
200 background-image: -ms-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* IE10 */
201 background-image: -o-linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/); /* Opera 11.10+ */
202 background-image: linear-gradient( #ddd /*{b-body-background-start}*/, #ccc /*{b-body-background-end}*/);
203}
204.ui-overlay-b {
205 background-image: none;
206 border-width: 0;
207}
208.ui-body-b,
209.ui-body-b input,
210.ui-body-b select,
211.ui-body-b textarea,
212.ui-body-b button {
213 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
214}
215.ui-body-b .ui-link-inherit {
216 color: #333 /*{b-body-color}*/;
217}
218.ui-body-b .ui-link {
219 color: #2489ce /*{b-body-link-color}*/;
220 font-weight: bold;
221}
222.ui-body-b .ui-link:visited {
223 color: #2489ce /*{b-body-link-visited}*/;
224}
225.ui-body-b .ui-link:hover {
226 color: #2489ce /*{b-body-link-hover}*/;
227}
228.ui-body-b .ui-link:active {
229 color: #2489ce /*{b-body-link-active}*/;
230}
231.ui-btn-up-b {
232 border: 1px solid #044062 /*{b-bup-border}*/;
233 background: #396b9e /*{b-bup-background-color}*/;
234 font-weight: bold;
235 color: #fff /*{b-bup-color}*/;
236 text-shadow: 0 /*{b-bup-shadow-x}*/ 1px /*{b-bup-shadow-y}*/ 0 /*{b-bup-shadow-radius}*/ #194b7e /*{b-bup-shadow-color}*/;
237 background-image: -webkit-gradient(linear, left top, left bottom, from( #5f9cc5 /*{b-bup-background-start}*/), to( #396b9e /*{b-bup-background-end}*/)); /* Saf4+, Chrome */
238 background-image: -webkit-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
239 background-image: -moz-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* FF3.6 */
240 background-image: -ms-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* IE10 */
241 background-image: -o-linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/); /* Opera 11.10+ */
242 background-image: linear-gradient( #5f9cc5 /*{b-bup-background-start}*/, #396b9e /*{b-bup-background-end}*/);
243}
244.ui-btn-up-b:visited,
245.ui-btn-up-b a.ui-link-inherit {
246 color: #fff /*{b-bup-color}*/;
247}
248.ui-btn-hover-b {
249 border: 1px solid #00415e /*{b-bhover-border}*/;
250 background: #4b88b6 /*{b-bhover-background-color}*/;
251 font-weight: bold;
252 color: #fff /*{b-bhover-color}*/;
253 text-shadow: 0 /*{b-bhover-shadow-x}*/ 1px /*{b-bhover-shadow-y}*/ 0 /*{b-bhover-shadow-radius}*/ #194b7e /*{b-bhover-shadow-color}*/;
254 background-image: -webkit-gradient(linear, left top, left bottom, from( #6facd5 /*{b-bhover-background-start}*/), to( #4272a4 /*{b-bhover-background-end}*/)); /* Saf4+, Chrome */
255 background-image: -webkit-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
256 background-image: -moz-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* FF3.6 */
257 background-image: -ms-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* IE10 */
258 background-image: -o-linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/); /* Opera 11.10+ */
259 background-image: linear-gradient( #6facd5 /*{b-bhover-background-start}*/, #4272a4 /*{b-bhover-background-end}*/);
260}
261.ui-btn-hover-b:visited,
262.ui-btn-hover-b:hover,
263.ui-btn-hover-b a.ui-link-inherit {
264 color: #fff /*{b-bhover-color}*/;
265}
266.ui-btn-down-b {
267 border: 1px solid #225377 /*{b-bdown-border}*/;
268 background: #4e89c5 /*{b-bdown-background-color}*/;
269 font-weight: bold;
270 color: #fff /*{b-bdown-color}*/;
271 text-shadow: 0 /*{b-bdown-shadow-x}*/ 1px /*{b-bdown-shadow-y}*/ 0 /*{b-bdown-shadow-radius}*/ #194b7e /*{b-bdown-shadow-color}*/;
272 background-image: -webkit-gradient(linear, left top, left bottom, from( #295b8e /*{b-bdown-background-start}*/), to( #3e79b5 /*{b-bdown-background-end}*/)); /* Saf4+, Chrome */
273 background-image: -webkit-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
274 background-image: -moz-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* FF3.6 */
275 background-image: -ms-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* IE10 */
276 background-image: -o-linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/); /* Opera 11.10+ */
277 background-image: linear-gradient( #295b8e /*{b-bdown-background-start}*/, #3e79b5 /*{b-bdown-background-end}*/);
278}
279.ui-btn-down-b:visited,
280.ui-btn-down-b:hover,
281.ui-btn-down-b a.ui-link-inherit {
282 color: #fff /*{b-bdown-color}*/;
283}
284.ui-btn-up-b,
285.ui-btn-hover-b,
286.ui-btn-down-b {
287 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
288 text-decoration: none;
289}
290/* C
291-----------------------------------------------------------------------------------------------------------*/
292.ui-bar-c {
293 border: 1px solid #b3b3b3 /*{c-bar-border}*/;
294 background: #eee /*{c-bar-background-color}*/;
295 color: #3e3e3e /*{c-bar-color}*/;
296 font-weight: bold;
297 text-shadow: 0 /*{c-bar-shadow-x}*/ 1px /*{c-bar-shadow-y}*/ 0 /*{c-bar-shadow-radius}*/ #fff /*{c-bar-shadow-color}*/;
298 background-image: -webkit-gradient(linear, left top, left bottom, from( #f0f0f0 /*{c-bar-background-start}*/), to( #ddd /*{c-bar-background-end}*/)); /* Saf4+, Chrome */
299 background-image: -webkit-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
300 background-image: -moz-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* FF3.6 */
301 background-image: -ms-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* IE10 */
302 background-image: -o-linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/); /* Opera 11.10+ */
303 background-image: linear-gradient( #f0f0f0 /*{c-bar-background-start}*/, #ddd /*{c-bar-background-end}*/);
304}
305.ui-bar-c .ui-link-inherit {
306 color: #3e3e3e /*{c-bar-color}*/;
307}
308.ui-bar-c a.ui-link {
309 color: #7cc4e7 /*{c-bar-link-color}*/;
310 font-weight: bold;
311}
312.ui-bar-c a.ui-link:visited {
313 color: #2489ce /*{c-bar-link-visited}*/;
314}
315.ui-bar-c a.ui-link:hover {
316 color: #2489ce /*{c-bar-link-hover}*/;
317}
318.ui-bar-c a.ui-link:active {
319 color: #2489ce /*{c-bar-link-active}*/;
320}
321.ui-bar-c,
322.ui-bar-c input,
323.ui-bar-c select,
324.ui-bar-c textarea,
325.ui-bar-c button {
326 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
327}
328.ui-body-c,
329.ui-overlay-c {
330 border: 1px solid #aaa /*{c-body-border}*/;
331 color: #333 /*{c-body-color}*/;
332 text-shadow: 0 /*{c-body-shadow-x}*/ 1px /*{c-body-shadow-y}*/ 0 /*{c-body-shadow-radius}*/ #fff /*{c-body-shadow-color}*/;
333 background: #f9f9f9 /*{c-body-background-color}*/;
334 background-image: -webkit-gradient(linear, left top, left bottom, from( #f9f9f9 /*{c-body-background-start}*/), to( #eee /*{c-body-background-end}*/)); /* Saf4+, Chrome */
335 background-image: -webkit-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
336 background-image: -moz-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* FF3.6 */
337 background-image: -ms-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* IE10 */
338 background-image: -o-linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/); /* Opera 11.10+ */
339 background-image: linear-gradient( #f9f9f9 /*{c-body-background-start}*/, #eee /*{c-body-background-end}*/);
340}
341.ui-overlay-c {
342 background-image: none;
343 border-width: 0;
344}
345.ui-body-c,
346.ui-body-c input,
347.ui-body-c select,
348.ui-body-c textarea,
349.ui-body-c button {
350 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
351}
352.ui-body-c .ui-link-inherit {
353 color: #333 /*{c-body-color}*/;
354}
355.ui-body-c .ui-link {
356 color: #2489ce /*{c-body-link-color}*/;
357 font-weight: bold;
358}
359.ui-body-c .ui-link:visited {
360 color: #2489ce /*{c-body-link-visited}*/;
361}
362.ui-body-c .ui-link:hover {
363 color: #2489ce /*{c-body-link-hover}*/;
364}
365.ui-body-c .ui-link:active {
366 color: #2489ce /*{c-body-link-active}*/;
367}
368.ui-btn-up-c {
369 border: 1px solid #ccc /*{c-bup-border}*/;
370 background: #eee /*{c-bup-background-color}*/;
371 font-weight: bold;
372 color: #222 /*{c-bup-color}*/;
373 text-shadow: 0 /*{c-bup-shadow-x}*/ 1px /*{c-bup-shadow-y}*/ 0 /*{c-bup-shadow-radius}*/ #fff /*{c-bup-shadow-color}*/;
374 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff /*{c-bup-background-start}*/), to( #f1f1f1 /*{c-bup-background-end}*/)); /* Saf4+, Chrome */
375 background-image: -webkit-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
376 background-image: -moz-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* FF3.6 */
377 background-image: -ms-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* IE10 */
378 background-image: -o-linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/); /* Opera 11.10+ */
379 background-image: linear-gradient( #fff /*{c-bup-background-start}*/, #f1f1f1 /*{c-bup-background-end}*/);
380}
381.ui-btn-up-c:visited,
382.ui-btn-up-c a.ui-link-inherit {
383 color: #2f3e46 /*{c-bup-color}*/;
384}
385.ui-btn-hover-c {
386 border: 1px solid #bbb /*{c-bhover-border}*/;
387 background: #dfdfdf /*{c-bhover-background-color}*/;
388 font-weight: bold;
389 color: #222 /*{c-bhover-color}*/;
390 text-shadow: 0 /*{c-bhover-shadow-x}*/ 1px /*{c-bhover-shadow-y}*/ 0 /*{c-bhover-shadow-radius}*/ #fff /*{c-bhover-shadow-color}*/;
391 background-image: -webkit-gradient(linear, left top, left bottom, from( #f6f6f6 /*{c-bhover-background-start}*/), to( #e0e0e0 /*{c-bhover-background-end}*/)); /* Saf4+, Chrome */
392 background-image: -webkit-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
393 background-image: -moz-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* FF3.6 */
394 background-image: -ms-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* IE10 */
395 background-image: -o-linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/); /* Opera 11.10+ */
396 background-image: linear-gradient( #f6f6f6 /*{c-bhover-background-start}*/, #e0e0e0 /*{c-bhover-background-end}*/);
397}
398.ui-btn-hover-c:visited,
399.ui-btn-hover-c:hover,
400.ui-btn-hover-c a.ui-link-inherit {
401 color: #2f3e46 /*{c-bhover-color}*/;
402}
403.ui-btn-down-c {
404 border: 1px solid #bbb /*{c-bdown-border}*/;
405 background: #d6d6d6 /*{c-bdown-background-color}*/;
406 font-weight: bold;
407 color: #222 /*{c-bdown-color}*/;
408 text-shadow: 0 /*{c-bdown-shadow-x}*/ 1px /*{c-bdown-shadow-y}*/ 0 /*{c-bdown-shadow-radius}*/ #fff /*{c-bdown-shadow-color}*/;
409 background-image: -webkit-gradient(linear, left top, left bottom, from( #d0d0d0 /*{c-bdown-background-start}*/), to( #dfdfdf /*{c-bdown-background-end}*/)); /* Saf4+, Chrome */
410 background-image: -webkit-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
411 background-image: -moz-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* FF3.6 */
412 background-image: -ms-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* IE10 */
413 background-image: -o-linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/); /* Opera 11.10+ */
414 background-image: linear-gradient( #d0d0d0 /*{c-bdown-background-start}*/, #dfdfdf /*{c-bdown-background-end}*/);
415}
416.ui-btn-down-c:visited,
417.ui-btn-down-c:hover,
418.ui-btn-down-c a.ui-link-inherit {
419 color: #2f3e46 /*{c-bdown-color}*/;
420}
421.ui-btn-up-c,
422.ui-btn-hover-c,
423.ui-btn-down-c {
424 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
425 text-decoration: none;
426}
427/* D
428-----------------------------------------------------------------------------------------------------------*/
429.ui-bar-d {
430 border: 1px solid #bbb /*{d-bar-border}*/;
431 background: #bbb /*{d-bar-background-color}*/;
432 color: #333 /*{d-bar-color}*/;
433 font-weight: bold;
434 text-shadow: 0 /*{d-bar-shadow-x}*/ 1px /*{d-bar-shadow-y}*/ 0 /*{d-bar-shadow-radius}*/ #eee /*{d-bar-shadow-color}*/;
435 background-image: -webkit-gradient(linear, left top, left bottom, from( #ddd /*{d-bar-background-start}*/), to( #bbb /*{d-bar-background-end}*/)); /* Saf4+, Chrome */
436 background-image: -webkit-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
437 background-image: -moz-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* FF3.6 */
438 background-image: -ms-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* IE10 */
439 background-image: -o-linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/); /* Opera 11.10+ */
440 background-image: linear-gradient( #ddd /*{d-bar-background-start}*/, #bbb /*{d-bar-background-end}*/);
441}
442.ui-bar-d,
443.ui-bar-d input,
444.ui-bar-d select,
445.ui-bar-d textarea,
446.ui-bar-d button {
447 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
448}
449.ui-bar-d .ui-link-inherit {
450 color: #333 /*{d-bar-color}*/;
451}
452.ui-bar-d a.ui-link {
453 color: #2489ce /*{d-bar-link-color}*/;
454 font-weight: bold;
455}
456.ui-bar-d a.ui-link:visited {
457 color: #2489ce /*{d-bar-link-visited}*/;
458}
459.ui-bar-d a.ui-link:hover {
460 color: #2489ce /*{d-bar-link-hover}*/;
461}
462.ui-bar-d a.ui-link:active {
463 color: #2489ce /*{d-bar-link-active}*/;
464}
465.ui-body-d,
466.ui-overlay-d {
467 border: 1px solid #bbb /*{d-body-border}*/;
468 color: #333 /*{d-body-color}*/;
469 text-shadow: 0 /*{d-body-shadow-x}*/ 1px /*{d-body-shadow-y}*/ 0 /*{d-body-shadow-radius}*/ #fff /*{d-body-shadow-color}*/;
470 background: #fff /*{d-body-background-color}*/;
471 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff /*{d-body-background-start}*/), to( #fff /*{d-body-background-end}*/)); /* Saf4+, Chrome */
472 background-image: -webkit-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
473 background-image: -moz-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* FF3.6 */
474 background-image: -ms-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* IE10 */
475 background-image: -o-linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/); /* Opera 11.10+ */
476 background-image: linear-gradient( #fff /*{d-body-background-start}*/, #fff /*{d-body-background-end}*/);
477}
478.ui-overlay-d {
479 background-image: none;
480 border-width: 0;
481}
482.ui-body-d,
483.ui-body-d input,
484.ui-body-d select,
485.ui-body-d textarea,
486.ui-body-d button {
487 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
488}
489.ui-body-d .ui-link-inherit {
490 color: #333 /*{d-body-color}*/;
491}
492.ui-body-d .ui-link {
493 color: #2489ce /*{d-body-link-color}*/;
494 font-weight: bold;
495}
496.ui-body-d .ui-link:visited {
497 color: #2489ce /*{d-body-link-visited}*/;
498}
499.ui-body-d .ui-link:hover {
500 color: #2489ce /*{d-body-link-hover}*/;
501}
502.ui-body-d .ui-link:active {
503 color: #2489ce /*{d-body-link-active}*/;
504}
505.ui-btn-up-d {
506 border: 1px solid #bbb /*{d-bup-border}*/;
507 background: #fff /*{d-bup-background-color}*/;
508 font-weight: bold;
509 color: #333 /*{d-bup-color}*/;
510 text-shadow: 0 /*{d-bup-shadow-x}*/ 1px /*{d-bup-shadow-y}*/ 0 /*{d-bup-shadow-radius}*/ #fff /*{d-bup-shadow-color}*/;
511 background-image: -webkit-gradient(linear, left top, left bottom, from( #fafafa /*{d-bup-background-start}*/), to( #f6f6f6 /*{d-bup-background-end}*/)); /* Saf4+, Chrome */
512 background-image: -webkit-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
513 background-image: -moz-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* FF3.6 */
514 background-image: -ms-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* IE10 */
515 background-image: -o-linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/); /* Opera 11.10+ */
516 background-image: linear-gradient( #fafafa /*{d-bup-background-start}*/, #f6f6f6 /*{d-bup-background-end}*/);
517}
518.ui-btn-up-d:visited,
519.ui-btn-up-d a.ui-link-inherit {
520 color: #333 /*{d-bup-color}*/;
521}
522.ui-btn-hover-d {
523 border: 1px solid #aaa /*{d-bhover-border}*/;
524 background: #eee /*{d-bhover-background-color}*/;
525 font-weight: bold;
526 color: #333 /*{d-bhover-color}*/;
527 cursor: pointer;
528 text-shadow: 0 /*{d-bhover-shadow-x}*/ 1px /*{d-bhover-shadow-y}*/ 0 /*{d-bhover-shadow-radius}*/ #fff /*{d-bhover-shadow-color}*/;
529 background-image: -webkit-gradient(linear, left top, left bottom, from( #eee /*{d-bhover-background-start}*/), to( #fff /*{d-bhover-background-end}*/)); /* Saf4+, Chrome */
530 background-image: -webkit-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
531 background-image: -moz-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* FF3.6 */
532 background-image: -ms-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* IE10 */
533 background-image: -o-linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/); /* Opera 11.10+ */
534 background-image: linear-gradient( #eee /*{d-bhover-background-start}*/, #fff /*{d-bhover-background-end}*/);
535}
536.ui-btn-hover-d:visited,
537.ui-btn-hover-d:hover,
538.ui-btn-hover-d a.ui-link-inherit {
539 color: #333 /*{d-bhover-color}*/;
540}
541.ui-btn-down-d {
542 border: 1px solid #aaa /*{d-bdown-border}*/;
543 background: #eee /*{d-bdown-background-color}*/;
544 font-weight: bold;
545 color: #333 /*{d-bdown-color}*/;
546 text-shadow: 0 /*{d-bdown-shadow-x}*/ 1px /*{d-bdown-shadow-y}*/ 0 /*{d-bdown-shadow-radius}*/ #fff /*{d-bdown-shadow-color}*/;
547 background-image: -webkit-gradient(linear, left top, left bottom, from( #e5e5e5 /*{d-bdown-background-start}*/), to( #f2f2f2 /*{d-bdown-background-end}*/)); /* Saf4+, Chrome */
548 background-image: -webkit-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
549 background-image: -moz-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* FF3.6 */
550 background-image: -ms-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* IE10 */
551 background-image: -o-linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/); /* Opera 11.10+ */
552 background-image: linear-gradient( #e5e5e5 /*{d-bdown-background-start}*/, #f2f2f2 /*{d-bdown-background-end}*/);
553}
554.ui-btn-down-d:visited,
555.ui-btn-down-d:hover,
556.ui-btn-down-d a.ui-link-inherit {
557 color: #333 /*{d-bdown-color}*/;
558}
559.ui-btn-up-d,
560.ui-btn-hover-d,
561.ui-btn-down-d {
562 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
563 text-decoration: none;
564}
565/* E
566-----------------------------------------------------------------------------------------------------------*/
567.ui-bar-e {
568 border: 1px solid #f7c942 /*{e-bar-border}*/;
569 background: #fadb4e /*{e-bar-background-color}*/;
570 color: #333 /*{e-bar-color}*/;
571 font-weight: bold;
572 text-shadow: 0 /*{e-bar-shadow-x}*/ 1px /*{e-bar-shadow-y}*/ 0 /*{e-bar-shadow-radius}*/ #fff /*{e-bar-shadow-color}*/;
573 background-image: -webkit-gradient(linear, left top, left bottom, from( #fceda7 /*{e-bar-background-start}*/), to( #fbef7e /*{e-bar-background-end}*/)); /* Saf4+, Chrome */
574 background-image: -webkit-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Chrome 10+, Saf5.1+ */
575 background-image: -moz-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* FF3.6 */
576 background-image: -ms-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* IE10 */
577 background-image: -o-linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/); /* Opera 11.10+ */
578 background-image: linear-gradient( #fceda7 /*{e-bar-background-start}*/, #fbef7e /*{e-bar-background-end}*/);
579}
580.ui-bar-e,
581.ui-bar-e input,
582.ui-bar-e select,
583.ui-bar-e textarea,
584.ui-bar-e button {
585 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
586}
587.ui-bar-e .ui-link-inherit {
588 color: #333 /*{e-bar-color}*/;
589}
590.ui-bar-e a.ui-link {
591 color: #2489ce /*{e-bar-link-color}*/;
592 font-weight: bold;
593}
594.ui-bar-e a.ui-link:visited {
595 color: #2489ce /*{e-bar-link-visited}*/;
596}
597.ui-bar-e a.ui-link:hover {
598 color: #2489ce /*{e-bar-link-hover}*/;
599}
600.ui-bar-e a.ui-link:active {
601 color: #2489ce /*{e-bar-link-active}*/;
602}
603.ui-body-e,
604.ui-overlay-e {
605 border: 1px solid #f7c942 /*{e-body-border}*/;
606 color: #222 /*{e-body-color}*/;
607 text-shadow: 0 /*{e-body-shadow-x}*/ 1px /*{e-body-shadow-y}*/ 0 /*{e-body-shadow-radius}*/ #fff /*{e-body-shadow-color}*/;
608 background: #fff9df /*{e-body-background-color}*/;
609 background-image: -webkit-gradient(linear, left top, left bottom, from( #fffadf /*{e-body-background-start}*/), to( #fff3a5 /*{e-body-background-end}*/)); /* Saf4+, Chrome */
610 background-image: -webkit-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Chrome 10+, Saf5.1+ */
611 background-image: -moz-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* FF3.6 */
612 background-image: -ms-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* IE10 */
613 background-image: -o-linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/); /* Opera 11.10+ */
614 background-image: linear-gradient( #fffadf /*{e-body-background-start}*/, #fff3a5 /*{e-body-background-end}*/);
615}
616.ui-overlay-e {
617 background-image: none;
618 border-width: 0;
619}
620.ui-body-e,
621.ui-body-e input,
622.ui-body-e select,
623.ui-body-e textarea,
624.ui-body-e button {
625 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
626}
627.ui-body-e .ui-link-inherit {
628 color: #222 /*{e-body-color}*/;
629}
630.ui-body-e .ui-link {
631 color: #2489ce /*{e-body-link-color}*/;
632 font-weight: bold;
633}
634.ui-body-e .ui-link:visited {
635 color: #2489ce /*{e-body-link-visited}*/;
636}
637.ui-body-e .ui-link:hover {
638 color: #2489ce /*{e-body-link-hover}*/;
639}
640.ui-body-e .ui-link:active {
641 color: #2489ce /*{e-body-link-active}*/;
642}
643.ui-btn-up-e {
644 border: 1px solid #f4c63f /*{e-bup-border}*/;
645 background: #fadb4e /*{e-bup-background-color}*/;
646 font-weight: bold;
647 color: #222 /*{e-bup-color}*/;
648 text-shadow: 0 /*{e-bup-shadow-x}*/ 1px /*{e-bup-shadow-y}*/ 0 /*{e-bup-shadow-radius}*/ #fff /*{e-bup-shadow-color}*/;
649 background-image: -webkit-gradient(linear, left top, left bottom, from( #ffefaa /*{e-bup-background-start}*/), to( #ffe155 /*{e-bup-background-end}*/)); /* Saf4+, Chrome */
650 background-image: -webkit-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Chrome 10+, Saf5.1+ */
651 background-image: -moz-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* FF3.6 */
652 background-image: -ms-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* IE10 */
653 background-image: -o-linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/); /* Opera 11.10+ */
654 background-image: linear-gradient( #ffefaa /*{e-bup-background-start}*/, #ffe155 /*{e-bup-background-end}*/);
655}
656.ui-btn-up-e:visited,
657.ui-btn-up-e a.ui-link-inherit {
658 color: #222 /*{e-bup-color}*/;
659}
660.ui-btn-hover-e {
661 border: 1px solid #f2c43d /*{e-bhover-border}*/;
662 background: #fbe26f /*{e-bhover-background-color}*/;
663 font-weight: bold;
664 color: #111 /*{e-bhover-color}*/;
665 text-shadow: 0 /*{e-bhover-shadow-x}*/ 1px /*{e-bhover-shadow-y}*/ 0 /*{e-bhover-shadow-radius}*/ #fff /*{e-bhover-shadow-color}*/;
666 background-image: -webkit-gradient(linear, left top, left bottom, from( #fff5ba /*{e-bhover-background-start}*/), to( #fbdd52 /*{e-bhover-background-end}*/)); /* Saf4+, Chrome */
667 background-image: -webkit-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Chrome 10+, Saf5.1+ */
668 background-image: -moz-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* FF3.6 */
669 background-image: -ms-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* IE10 */
670 background-image: -o-linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/); /* Opera 11.10+ */
671 background-image: linear-gradient( #fff5ba /*{e-bhover-background-start}*/, #fbdd52 /*{e-bhover-background-end}*/);
672}
673.ui-btn-hover-e:visited,
674.ui-btn-hover-e:hover,
675.ui-btn-hover-e a.ui-link-inherit {
676 color: #333 /*{e-bhover-color}*/;
677}
678.ui-btn-down-e {
679 border: 1px solid #f2c43d /*{e-bdown-border}*/;
680 background: #fceda7 /*{e-bdown-background-color}*/;
681 font-weight: bold;
682 color: #111 /*{e-bdown-color}*/;
683 text-shadow: 0 /*{e-bdown-shadow-x}*/ 1px /*{e-bdown-shadow-y}*/ 0 /*{e-bdown-shadow-radius}*/ #fff /*{e-bdown-shadow-color}*/;
684 background-image: -webkit-gradient(linear, left top, left bottom, from( #f8d94c /*{e-bdown-background-start}*/), to( #fadb4e /*{e-bdown-background-end}*/)); /* Saf4+, Chrome */
685 background-image: -webkit-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Chrome 10+, Saf5.1+ */
686 background-image: -moz-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* FF3.6 */
687 background-image: -ms-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* IE10 */
688 background-image: -o-linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/); /* Opera 11.10+ */
689 background-image: linear-gradient( #f8d94c /*{e-bdown-background-start}*/, #fadb4e /*{e-bdown-background-end}*/);
690}
691.ui-btn-down-e:visited,
692.ui-btn-down-e:hover,
693.ui-btn-down-e a.ui-link-inherit {
694 color: #333 /*{e-bdown-color}*/;
695}
696.ui-btn-up-e,
697.ui-btn-hover-e,
698.ui-btn-down-e {
699 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
700 text-decoration: none;
701}
702/* Structure */
703/* links within "buttons"
704-----------------------------------------------------------------------------------------------------------*/
705a.ui-link-inherit {
706 text-decoration: none !important;
707}
708/* Active class used as the "on" state across all themes
709-----------------------------------------------------------------------------------------------------------*/
710.ui-btn-active {
711 border: 1px solid #2373a5 /*{global-active-border}*/;
712 background: #5393c5 /*{global-active-background-color}*/;
713 font-weight: bold;
714 color: #fff /*{global-active-color}*/;
715 cursor: pointer;
716 text-shadow: 0 /*{global-active-shadow-x}*/ 1px /*{global-active-shadow-y}*/ 0 /*{global-active-shadow-radius}*/ #3373a5 /*{global-active-shadow-color}*/;
717 text-decoration: none;
718 background-image: -webkit-gradient(linear, left top, left bottom, from( #5393c5 /*{global-active-background-start}*/), to( #6facd5 /*{global-active-background-end}*/)); /* Saf4+, Chrome */
719 background-image: -webkit-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Chrome 10+, Saf5.1+ */
720 background-image: -moz-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* FF3.6 */
721 background-image: -ms-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* IE10 */
722 background-image: -o-linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/); /* Opera 11.10+ */
723 background-image: linear-gradient( #5393c5 /*{global-active-background-start}*/, #6facd5 /*{global-active-background-end}*/);
724 font-family: Helvetica, Arial, sans-serif /*{global-font-family}*/;
725}
726.ui-btn-active:visited,
727.ui-btn-active:hover,
728.ui-btn-active a.ui-link-inherit {
729 color: #fff /*{global-active-color}*/;
730}
731/* button inner top highlight
732-----------------------------------------------------------------------------------------------------------*/
733.ui-btn-inner {
734 border-top: 1px solid #fff;
735 border-color: rgba(255,255,255,.3);
736}
737/* corner rounding classes
738-----------------------------------------------------------------------------------------------------------*/
739.ui-corner-all {
740 -webkit-border-radius: .6em /*{global-radii-blocks}*/;
741 border-radius: .6em /*{global-radii-blocks}*/;
742}
743/* Form field separator
744-----------------------------------------------------------------------------------------------------------*/
745.ui-br {
746 border-color: rgb(130,130,130);
747 border-color: rgba(130,130,130,.3);
748 border-style: solid;
749}
750/* Interaction cues
751-----------------------------------------------------------------------------------------------------------*/
752.ui-disabled {
753 filter: Alpha(Opacity=30);
754 opacity: .3;
755 zoom: 1;
756}
757.ui-disabled,
758.ui-disabled a {
759 cursor: default !important;
760 pointer-events: none;
761}
762/* Icons
763-----------------------------------------------------------------------------------------------------------*/
764.ui-icon,
765.ui-icon-searchfield:after {
766 background: #666 /*{global-icon-color}*/;
767 background: rgba(0,0,0,.4) /*{global-icon-disc}*/;
768 background-image: url(images/icons-18-white.png) /*{global-icon-set}*/;
769 background-repeat: no-repeat;
770 -webkit-border-radius: 9px;
771 border-radius: 9px;
772}
773/* Alt icon color
774-----------------------------------------------------------------------------------------------------------*/
775.ui-icon-alt .ui-icon,
776.ui-icon-alt .ui-icon-searchfield:after {
777 background-color: #fff;
778 background-color: rgba(255,255,255,.3);
779 background-image: url(images/icons-18-black.png);
780 background-repeat: no-repeat;
781}
782/* No disc
783-----------------------------------------------------------------------------------------------------------*/
784.ui-icon-nodisc .ui-icon,
785.ui-icon-nodisc .ui-icon-searchfield:after,
786.ui-icon-nodisc .ui-icon-alt .ui-icon,
787.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after {
788 background-color: transparent;
789}
790/* Icon sprite
791-----------------------------------------------------------------------------------------------------------*/
792/* plus minus */
793.ui-icon-plus {
794 background-position: -1px -1px;
795}
796.ui-icon-minus {
797 background-position: -37px -1px;
798}
799/* delete/close */
800.ui-icon-delete {
801 background-position: -73px -1px;
802}
803/* arrows */
804.ui-icon-arrow-r {
805 background-position: -108px -1px;
806}
807.ui-icon-arrow-l {
808 background-position: -144px -1px;
809}
810.ui-icon-arrow-u {
811 background-position: -180px -1px;
812}
813.ui-icon-arrow-d {
814 background-position: -216px -1px;
815}
816/* misc */
817.ui-icon-check {
818 background-position: -252px -1px;
819}
820.ui-icon-gear {
821 background-position: -288px -1px;
822}
823.ui-icon-refresh {
824 background-position: -323px -1px;
825}
826.ui-icon-forward {
827 background-position: -360px -1px;
828}
829.ui-icon-back {
830 background-position: -396px -1px;
831}
832.ui-icon-grid {
833 background-position: -432px -1px;
834}
835.ui-icon-star {
836 background-position: -467px -1px;
837}
838.ui-icon-alert {
839 background-position: -503px -1px;
840}
841.ui-icon-info {
842 background-position: -539px -1px;
843}
844.ui-icon-home {
845 background-position: -575px -1px;
846}
847/* search */
848.ui-icon-search,
849.ui-icon-searchfield:after {
850 background-position: -611px -1px;
851}
852/* checkbox radio */
853.ui-icon-checkbox-on {
854 background-position: -647px -1px;
855}
856.ui-icon-checkbox-off {
857 background-position: -683px -1px;
858}
859.ui-icon-radio-on {
860 background-position: -718px -1px;
861}
862.ui-icon-radio-off {
863 background-position: -754px -1px;
864}
865/* menu edit */
866.ui-icon-bars {
867 background-position: -788px -1px;
868}
869.ui-icon-edit {
870 background-position: -824px -1px;
871}
872/* HD/"retina" sprite
873-----------------------------------------------------------------------------------------------------------*/
874@media only screen and (-webkit-min-device-pixel-ratio: 1.3),
875 only screen and (min--moz-device-pixel-ratio: 1.3),
876 only screen and (min-resolution: 200dpi) {
877
878 .ui-icon-plus, .ui-icon-minus, .ui-icon-delete, .ui-icon-arrow-r,
879 .ui-icon-arrow-l, .ui-icon-arrow-u, .ui-icon-arrow-d, .ui-icon-check,
880 .ui-icon-gear, .ui-icon-refresh, .ui-icon-forward, .ui-icon-back,
881 .ui-icon-grid, .ui-icon-star, .ui-icon-alert, .ui-icon-info, .ui-icon-home, .ui-icon-bars, .ui-icon-edit,
882 .ui-icon-search, .ui-icon-searchfield:after,
883 .ui-icon-checkbox-off, .ui-icon-checkbox-on, .ui-icon-radio-off, .ui-icon-radio-on {
884 background-image: url(images/icons-36-white.png);
885 -moz-background-size: 864px 18px;
886 -o-background-size: 864px 18px;
887 -webkit-background-size: 864px 18px;
888 background-size: 864px 18px;
889 }
890 .ui-icon-alt .ui-icon {
891 background-image: url(images/icons-36-black.png);
892 }
893 .ui-icon-plus {
894 background-position: 0 50%;
895 }
896 .ui-icon-minus {
897 background-position: -36px 50%;
898 }
899 .ui-icon-delete {
900 background-position: -72px 50%;
901 }
902 .ui-icon-arrow-r {
903 background-position: -108px 50%;
904 }
905 .ui-icon-arrow-l {
906 background-position: -144px 50%;
907 }
908 .ui-icon-arrow-u {
909 background-position: -179px 50%;
910 }
911 .ui-icon-arrow-d {
912 background-position: -215px 50%;
913 }
914 .ui-icon-check {
915 background-position: -252px 50%;
916 }
917 .ui-icon-gear {
918 background-position: -287px 50%;
919 }
920 .ui-icon-refresh {
921 background-position: -323px 50%;
922 }
923 .ui-icon-forward {
924 background-position: -360px 50%;
925 }
926 .ui-icon-back {
927 background-position: -395px 50%;
928 }
929 .ui-icon-grid {
930 background-position: -431px 50%;
931 }
932 .ui-icon-star {
933 background-position: -467px 50%;
934 }
935 .ui-icon-alert {
936 background-position: -503px 50%;
937 }
938 .ui-icon-info {
939 background-position: -538px 50%;
940 }
941 .ui-icon-home {
942 background-position: -575px 50%;
943 }
944 .ui-icon-search,
945 .ui-icon-searchfield:after {
946 background-position: -611px 50%;
947 }
948 .ui-icon-checkbox-on {
949 background-position: -647px 50%;
950 }
951 .ui-icon-checkbox-off {
952 background-position: -683px 50%;
953 }
954 .ui-icon-radio-on {
955 background-position: -718px 50%;
956 }
957 .ui-icon-radio-off {
958 background-position: -754px 50%;
959 }
960 .ui-icon-bars {
961 background-position: -788px 50%;
962
963 }.ui-icon-edit {
964 background-position: -824px 50%;
965 }
966}
967/* checks,radios */
968.ui-checkbox .ui-icon,
969.ui-selectmenu-list .ui-icon {
970 -webkit-border-radius: 3px;
971 border-radius: 3px;
972}
973.ui-icon-checkbox-off,
974.ui-icon-radio-off {
975 background-color: transparent;
976}
977.ui-checkbox-on .ui-icon,
978.ui-radio-on .ui-icon {
979 background-color: #4596ce /*{global-active-background-color}*/; /* NOTE: this hex should match the active state color. It's repeated here for cascade */
980}
981/* loading icon */
982.ui-icon-loading {
983 background: url(images/ajax-loader.gif);
984 background-size: 46px 46px;
985}
986/* Button corner class
987-----------------------------------------------------------------------------------------------------------*/
988.ui-btn-corner-all {
989 -webkit-border-radius: 1em /*{global-radii-buttons}*/;
990 border-radius: 1em /*{global-radii-buttons}*/;
991}
992/* radius clip workaround for cleaning up corner trapping */
993.ui-corner-all,
994.ui-btn-corner-all {
995 -webkit-background-clip: padding;
996 background-clip: padding-box;
997}
998/* Overlay / modal
999-----------------------------------------------------------------------------------------------------------*/
1000.ui-overlay {
1001 background: #666;
1002 filter: Alpha(Opacity=50);
1003 opacity: .5;
1004 position: absolute;
1005 width: 100%;
1006 height: 100%;
1007}
1008.ui-overlay-shadow {
1009 -moz-box-shadow: 0 0 12px rgba(0,0,0,.6);
1010 -webkit-box-shadow: 0 0 12px rgba(0,0,0,.6);
1011 box-shadow: 0 0 12px rgba(0,0,0,.6);
1012}
1013.ui-shadow {
1014 -moz-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/;
1015 -webkit-box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/;
1016 box-shadow: 0 1px 3px /*{global-box-shadow-size}*/ rgba(0,0,0,.2) /*{global-box-shadow-color}*/
1017}
1018.ui-bar-a .ui-shadow,
1019.ui-bar-b .ui-shadow ,
1020.ui-bar-c .ui-shadow {
1021 -moz-box-shadow: 0 1px 0 rgba(255,255,255,.3);
1022 -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.3);
1023 box-shadow: 0 1px 0 rgba(255,255,255,.3);
1024}
1025.ui-shadow-inset {
1026 -moz-box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1027 -webkit-box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1028 box-shadow: inset 0 1px 4px rgba(0,0,0,.2);
1029}
1030.ui-icon-shadow {
1031 -moz-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1032 -webkit-box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1033 box-shadow: 0 1px 0 rgba(255,255,255,.4) /*{global-icon-shadow}*/;
1034}
1035/* Focus state - set here for specificity (note: these classes are added by JavaScript)
1036-----------------------------------------------------------------------------------------------------------*/
1037.ui-btn:focus, .ui-link-inherit:focus {
1038 outline: 0;
1039}
1040.ui-btn.ui-focus {
1041 z-index: 1;
1042}
1043.ui-focus,
1044.ui-btn:focus {
1045 -moz-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1046 -webkit-box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1047 box-shadow: inset 0 0 3px #387bbe /*{global-active-background-color}*/, 0 0 9px #387bbe /*{global-active-background-color}*/;
1048}
1049.ui-input-text.ui-focus,
1050.ui-input-search.ui-focus {
1051 -moz-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1052 -webkit-box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1053 box-shadow: 0 0 12px #387bbe /*{global-active-background-color}*/;
1054}
1055/* unset box shadow in browsers that don't do it right
1056-----------------------------------------------------------------------------------------------------------*/
1057.ui-mobile-nosupport-boxshadow * {
1058 -moz-box-shadow: none !important;
1059 -webkit-box-shadow: none !important;
1060 box-shadow: none !important;
1061}
1062/* ...and bring back focus */
1063.ui-mobile-nosupport-boxshadow .ui-focus,
1064.ui-mobile-nosupport-boxshadow .ui-btn:focus,
1065.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus {
1066 outline-width: 1px;
1067 outline-style: auto;
1068}
diff --git a/templates/index.html b/templates/index.html
deleted file mode 100644
index 6903a10..0000000
--- a/templates/index.html
+++ /dev/null
@@ -1,51 +0,0 @@
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>Page Title</title>
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6 <link rel="stylesheet" href="/static/vendor/jquery.mobile-1.3.2.css" />
7 <script src="/static/vendor/jquery-1.10.2.js"></script>
8 <script src="/static/vendor/jquery.mobile-1.3.2.js"></script>
9 </head>
10
11 <script type="text/javascript">
12 $(document).ready(function() {
13 $.ajax("/power-status/").done(function(data) {
14 for (key in data) {
15 var value = data[key] ? "on" : "off";
16 var key = key.replace("'", "-").replace(" ", "_");
17 $("#"+key).val(value).slider("refresh");
18 }
19 });
20 $("select[data-role=slider]").on("change", function() {
21 var data = {};
22 data[$(this).attr("data-name")] = $(this).val();
23 $.ajax({ url: "/power-status/", data: data, type: "POST" });
24 });
25 });
26 </script>
27
28 <body>
29 <div data-role="page">
30 <div data-role="header">
31 <h1>Appliances</h1>
32 </div><!-- /header -->
33
34 <div data-role="content">
35 <form>
36 {% for name, id in ports %}
37 <div class="ui-grid-a">
38 <div class="ui-block-a"><div class="ui-bar" style="height:60px">
39 <label for="{{ id }}">{{ name }}</label>
40 <select name="{{ id }}" id="{{ id }}" data-name="{{ name }}" data-role="slider">
41 <option value="off">Off</option>
42 <option value="on">On</option>
43 </select>
44 </div></div>
45 </div><!-- /grid-a -->
46 {% end %}
47 </form>
48 </div><!-- /content -->
49 </div>
50 </body>
51</html>
diff --git a/utils.py b/utils.py
deleted file mode 100644
index 2226108..0000000
--- a/utils.py
+++ /dev/null
@@ -1,16 +0,0 @@
1def decode_station_band(sta):
2 tx = sta["tx_rate"] / 1000
3 rx = sta["rx_rate"] / 1000
4 is_a = sta.get("is_11a", None)
5 is_n = sta.get("is_11n", False)
6
7 if is_n:
8 return "N"
9
10 if is_a:
11 return "A"
12
13 if not is_n and any((rx > 11, rx > 11)):
14 return "G"
15 else:
16 return "B"